From 7a8a023090527a97f3b0723adfbb0cec7bfd1c1b Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Wed, 30 Oct 2024 13:30:00 +0100 Subject: [PATCH 01/26] cu_cp,rrc: move rrc_state to rrc_ue.h --- include/srsran/rrc/rrc_ue.h | 3 +++ lib/rrc/ue/rrc_ue_context.h | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/srsran/rrc/rrc_ue.h b/include/srsran/rrc/rrc_ue.h index 259403f010..134c5e7a06 100644 --- a/include/srsran/rrc/rrc_ue.h +++ b/include/srsran/rrc/rrc_ue.h @@ -35,6 +35,9 @@ struct dl_dcch_msg_s; namespace srsran { namespace srs_cu_cp { +/// RRC states (3GPP 38.331 v15.5.1 Sec 4.2.1) +enum class rrc_state { idle = 0, connected, connected_inactive }; + class rrc_ue_controller { public: diff --git a/lib/rrc/ue/rrc_ue_context.h b/lib/rrc/ue/rrc_ue_context.h index fd1e61a488..41e6ceefda 100644 --- a/lib/rrc/ue/rrc_ue_context.h +++ b/lib/rrc/ue/rrc_ue_context.h @@ -20,9 +20,6 @@ namespace srsran { namespace srs_cu_cp { -/// RRC states (3GPP 38.331 v15.5.1 Sec 4.2.1) -enum class rrc_state { idle = 0, connected, connected_inactive }; - /// Holds the RRC UE context used by the UE object and all its procedures. class rrc_ue_context_t { From 6ebf84d1adfeaad2a9cb66886db530177f165f63 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 7 Nov 2024 12:56:11 +0100 Subject: [PATCH 02/26] cu_cp,rrc: add rrc connection state to ue metrics --- include/srsran/cu_cp/cu_cp_metrics_handler.h | 3 +++ include/srsran/rrc/rrc_ue.h | 3 +++ lib/cu_cp/ue_manager/cu_cp_ue_impl.h | 2 +- lib/cu_cp/ue_manager/ue_manager_impl.cpp | 6 ++++++ lib/rrc/ue/rrc_ue_impl.cpp | 5 +++++ lib/rrc/ue/rrc_ue_impl.h | 1 + .../cu_cp/metrics_handler/metrics_handler_test.cpp | 8 ++++++-- .../mobility/handover_reconfiguration_routine_test.cpp | 2 ++ 8 files changed, 27 insertions(+), 3 deletions(-) diff --git a/include/srsran/cu_cp/cu_cp_metrics_handler.h b/include/srsran/cu_cp/cu_cp_metrics_handler.h index ca52772e4d..ed670f1f5e 100644 --- a/include/srsran/cu_cp/cu_cp_metrics_handler.h +++ b/include/srsran/cu_cp/cu_cp_metrics_handler.h @@ -14,6 +14,7 @@ #include "srsran/ran/nr_cgi.h" #include "srsran/ran/pci.h" #include "srsran/ran/rnti.h" +#include "srsran/rrc/rrc_ue.h" #include #include @@ -29,6 +30,8 @@ struct metrics_report { gnb_du_id_t du_id; /// PCI of the UE's PCell. pci_t pci; + /// RRC connection state of the UE. + rrc_state rrc_connection_state; }; struct cell_info { nr_cell_global_id_t cgi; diff --git a/include/srsran/rrc/rrc_ue.h b/include/srsran/rrc/rrc_ue.h index 134c5e7a06..787e4c5221 100644 --- a/include/srsran/rrc/rrc_ue.h +++ b/include/srsran/rrc/rrc_ue.h @@ -290,6 +290,9 @@ class rrc_ue_control_message_handler /// \brief Get all SRBs of the UE. virtual static_vector get_srbs() = 0; + + /// \brief Get the RRC connection state of the UE. + virtual rrc_state get_rrc_state() const = 0; }; class rrc_ue_cu_cp_ue_notifier diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h index 7536cd9652..153fd4bb18 100644 --- a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h @@ -126,7 +126,7 @@ class cu_cp_ue : public cu_cp_ue_impl_interface rrc_ue_cu_cp_adapter& get_rrc_ue_cu_cp_adapter() { return rrc_ue_cu_cp_ev_notifier; } /// \brief Get the RRC UE of the UE. - rrc_ue_interface* get_rrc_ue() { return rrc_ue; } + rrc_ue_interface* get_rrc_ue() const { return rrc_ue; } private: // common context diff --git a/lib/cu_cp/ue_manager/ue_manager_impl.cpp b/lib/cu_cp/ue_manager/ue_manager_impl.cpp index 95bc054a4c..f836d57c59 100644 --- a/lib/cu_cp/ue_manager/ue_manager_impl.cpp +++ b/lib/cu_cp/ue_manager/ue_manager_impl.cpp @@ -237,6 +237,12 @@ std::vector ue_manager::handle_ue_metrics_report_reques ue_report.rnti = ue.second.get_c_rnti(); ue_report.du_id = ue.second.get_du_id(); ue_report.pci = ue.second.get_pci(); + + if (ue.second.get_rrc_ue() == nullptr) { + ue_report.rrc_connection_state = rrc_state::idle; + } else { + ue_report.rrc_connection_state = ue.second.get_rrc_ue()->get_rrc_ue_control_message_handler().get_rrc_state(); + } } return report; diff --git a/lib/rrc/ue/rrc_ue_impl.cpp b/lib/rrc/ue/rrc_ue_impl.cpp index 4354e4fca1..97fc301ca8 100644 --- a/lib/rrc/ue/rrc_ue_impl.cpp +++ b/lib/rrc/ue/rrc_ue_impl.cpp @@ -100,6 +100,11 @@ static_vector rrc_ue_impl::get_srbs() return srb_ids; } +rrc_state rrc_ue_impl::get_rrc_state() const +{ + return context.state; +} + void rrc_ue_impl::on_new_dl_ccch(const asn1::rrc_nr::dl_ccch_msg_s& dl_ccch_msg) { send_dl_ccch(dl_ccch_msg); diff --git a/lib/rrc/ue/rrc_ue_impl.h b/lib/rrc/ue/rrc_ue_impl.h index 94ea0ad1f5..424ea129e2 100644 --- a/lib/rrc/ue/rrc_ue_impl.h +++ b/lib/rrc/ue/rrc_ue_impl.h @@ -71,6 +71,7 @@ class rrc_ue_impl final : public rrc_ue_interface, public rrc_ue_controller byte_buffer handle_rrc_handover_command(byte_buffer cmd) override; void create_srb(const srb_creation_message& msg) override; static_vector get_srbs() override; + rrc_state get_rrc_state() const override; // rrc_ue_context_handler rrc_ue_reestablishment_context_response get_context() override; diff --git a/tests/unittests/cu_cp/metrics_handler/metrics_handler_test.cpp b/tests/unittests/cu_cp/metrics_handler/metrics_handler_test.cpp index d77d9585b8..a7a91e4ddd 100644 --- a/tests/unittests/cu_cp/metrics_handler/metrics_handler_test.cpp +++ b/tests/unittests/cu_cp/metrics_handler/metrics_handler_test.cpp @@ -45,7 +45,8 @@ TEST(metrics_handler_test, get_periodic_metrics_report_while_session_is_active) auto session = metrics.create_periodic_report_session(periodic_metric_report_request{period, &metrics_notifier}); // First report. - metrics_hdlr.next_metrics.ues.emplace_back(metrics_report::ue_info{to_rnti(1), int_to_gnb_du_id(0), pci_t{2}}); + metrics_hdlr.next_metrics.ues.emplace_back( + metrics_report::ue_info{to_rnti(1), int_to_gnb_du_id(0), pci_t{2}, rrc_state::connected}); metrics_hdlr.next_metrics.dus.emplace_back(metrics_report::du_info{ int_to_gnb_du_id(0), {metrics_report::cell_info{ @@ -59,10 +60,13 @@ TEST(metrics_handler_test, get_periodic_metrics_report_while_session_is_active) ASSERT_EQ(metrics_notifier.last_metrics_report->ues.size(), 1); ASSERT_EQ(metrics_notifier.last_metrics_report->ues[0].rnti, metrics_hdlr.next_metrics.ues[0].rnti); ASSERT_EQ(metrics_notifier.last_metrics_report->ues[0].pci, metrics_hdlr.next_metrics.ues[0].pci); + ASSERT_EQ(metrics_notifier.last_metrics_report->ues[0].rrc_connection_state, + metrics_hdlr.next_metrics.ues[0].rrc_connection_state); // Second report. metrics_notifier.last_metrics_report.reset(); - metrics_hdlr.next_metrics.ues.emplace_back(metrics_report::ue_info{to_rnti(2), int_to_gnb_du_id(0), pci_t{3}}); + metrics_hdlr.next_metrics.ues.emplace_back( + metrics_report::ue_info{to_rnti(2), int_to_gnb_du_id(0), pci_t{3}, rrc_state::connected}); for (unsigned i = 0; i != period.count(); ++i) { ASSERT_FALSE(metrics_notifier.last_metrics_report.has_value()); timers.tick(); diff --git a/tests/unittests/cu_cp/mobility/handover_reconfiguration_routine_test.cpp b/tests/unittests/cu_cp/mobility/handover_reconfiguration_routine_test.cpp index 7959ab60e9..51a6ed7f1b 100644 --- a/tests/unittests/cu_cp/mobility/handover_reconfiguration_routine_test.cpp +++ b/tests/unittests/cu_cp/mobility/handover_reconfiguration_routine_test.cpp @@ -135,6 +135,8 @@ struct dummy_rrc_ue : public rrc_ue_interface, public rrc_ue_controller { static_vector get_srbs() override { return srb_vec; } + rrc_state get_rrc_state() const override { return rrc_state::connected; }; + // RRC UE Setup proc notifier void on_new_dl_ccch(const asn1::rrc_nr::dl_ccch_msg_s& dl_ccch_msg) override{}; void on_ue_release_required(const ngap_cause_t& cause) override{}; From 772670564f72f6948085a88a9bdda16ba1d7c4b4 Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Mon, 11 Nov 2024 10:26:39 +0100 Subject: [PATCH 03/26] ofh: improves log of incomplete data notification --- lib/ofh/receiver/ofh_closed_rx_window_handler.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp b/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp index 0551036bc0..d19b3e28ff 100644 --- a/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp +++ b/lib/ofh/receiver/ofh_closed_rx_window_handler.cpp @@ -62,7 +62,7 @@ void closed_rx_window_handler::handle_uplink_context(slot_symbol_point symbol_po ctx_value.context.sector); } - logger.debug("Notifying UL symbol in slot '{}', symbol '{}' for sector#{}", + logger.debug("Notifying incomplete UL symbol in slot '{}', symbol '{}' for sector#{}", notification_context.slot, notification_context.symbol, notification_context.sector); @@ -93,5 +93,6 @@ void closed_rx_window_handler::handle_prach_context(slot_symbol_point symbol_poi ctx_value.context.sector); } - logger.debug("Notifying PRACH in slot '{}' for sector#{}", ctx_value.context.slot, ctx_value.context.sector); + logger.debug( + "Notifying incomplete PRACH in slot '{}' for sector#{}", ctx_value.context.slot, ctx_value.context.sector); } From 53d6bbe458e4c01e577be6d36b64dcf6e614e64d Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Fri, 8 Nov 2024 13:05:42 +0100 Subject: [PATCH 04/26] test: added test to FAPI that uses the maximum ammount of PDUs for the scheduler results. --- .../mac/mac_to_fapi_translator_test.cpp | 86 ++++++++ .../fapi_adaptor/mac/messages/helpers.cpp | 186 +++++++++++++++++- .../fapi_adaptor/mac/messages/helpers.h | 24 ++- 3 files changed, 288 insertions(+), 8 deletions(-) diff --git a/tests/unittests/fapi_adaptor/mac/mac_to_fapi_translator_test.cpp b/tests/unittests/fapi_adaptor/mac/mac_to_fapi_translator_test.cpp index 75b669f3cb..e6e151e28a 100644 --- a/tests/unittests/fapi_adaptor/mac/mac_to_fapi_translator_test.cpp +++ b/tests/unittests/fapi_adaptor/mac/mac_to_fapi_translator_test.cpp @@ -221,3 +221,89 @@ TEST(mac_to_fapi_translator, last_message_is_notified) ASSERT_TRUE(notifier_spy.has_on_last_message_method_called()); ASSERT_EQ(slot, notifier_spy.slot()); } + +TEST(mac_to_fapi_translator, dl_tti_message_with_all_pdus_passes) +{ + slot_message_gateway_spy gateway_spy; + slot_last_message_notifier_spy notifier_spy; + unsigned nof_prbs = 51U; + auto pm_tools = generate_precoding_matrix_tables(1); + auto uci_part2_tools = generate_uci_part2_correspondence(1); + mac_to_fapi_translator translator(srslog::fetch_basic_logger("FAPI"), + gateway_spy, + notifier_spy, + std::move(std::get<0>(pm_tools)), + std::move(std::get<0>(uci_part2_tools)), + nof_prbs); + + const unittests::mac_dl_sched_result_test_helper& result_test = + srsran::unittests::build_valid_mac_dl_sched_result_with_all_supported_pdus(); + const mac_dl_sched_result& result = result_test.result; + translator.on_new_downlink_scheduler_results(result); + + const fapi::ul_dci_request_message& ul_dci_msg = gateway_spy.ul_dci_request_msg(); + ASSERT_EQ(ul_dci_msg.pdus.size(), MAX_UL_PDCCH_PDUS_PER_SLOT); + + const fapi::dl_tti_request_message& dl_tti_msg = gateway_spy.dl_tti_request_msg(); + ASSERT_EQ(dl_tti_msg.pdus.size(), MAX_DL_PDUS_PER_SLOT); +} + +TEST(mac_to_fapi_translator, tx_data_message_with_all_pdus_passes) +{ + slot_message_gateway_spy gateway_spy; + slot_last_message_notifier_spy notifier_spy; + unsigned nof_prbs = 51U; + auto pm_tools = generate_precoding_matrix_tables(1); + auto uci_part2_tools = generate_uci_part2_correspondence(1); + mac_to_fapi_translator translator(srslog::fetch_basic_logger("FAPI"), + gateway_spy, + notifier_spy, + std::move(std::get<0>(pm_tools)), + std::move(std::get<0>(uci_part2_tools)), + nof_prbs); + + const unittests::mac_dl_sched_result_test_helper& result_test = + srsran::unittests::build_valid_mac_dl_sched_result_with_all_supported_pdus(); + const mac_dl_sched_result& result = result_test.result; + translator.on_new_downlink_scheduler_results(result); + + const mac_dl_data_result& data_result = srsran::unittests::build_valid_mac_data_result_with_all_supported_pdu(); + translator.on_new_downlink_data(data_result); + + const fapi::tx_data_request_message& tx_data_msg = gateway_spy.tx_data_request_msg(); + ASSERT_EQ(tx_data_msg.pdus.size(), + MAX_SI_PDUS_PER_SLOT + MAX_RAR_PDUS_PER_SLOT + MAX_UE_PDUS_PER_SLOT + MAX_PAGING_PDUS_PER_SLOT); + + const fapi::ul_dci_request_message& ul_dci_msg = gateway_spy.ul_dci_request_msg(); + ASSERT_EQ(ul_dci_msg.pdus.size(), MAX_UL_PDCCH_PDUS_PER_SLOT); + + const fapi::dl_tti_request_message& dl_tti_msg = gateway_spy.dl_tti_request_msg(); + ASSERT_EQ(dl_tti_msg.pdus.size(), MAX_DL_PDUS_PER_SLOT); +} + +TEST(mac_to_fapi_translator, ul_tti_message_with_all_pdus_passes) +{ + slot_message_gateway_spy gateway_spy; + slot_last_message_notifier_spy notifier_spy; + unsigned nof_prbs = 51U; + auto pm_tools = generate_precoding_matrix_tables(1); + auto uci_part2_tools = generate_uci_part2_correspondence(1); + mac_to_fapi_translator translator(srslog::fetch_basic_logger("FAPI"), + gateway_spy, + notifier_spy, + std::move(std::get<0>(pm_tools)), + std::move(std::get<0>(uci_part2_tools)), + nof_prbs); + + srslog::fetch_basic_logger("FAPI").set_level(srslog::basic_levels::debug); + + ASSERT_FALSE(gateway_spy.has_ul_tti_request_method_called()); + + const unittests::mac_ul_sched_result_test_helper& result_test = + srsran::unittests::build_valid_mac_ul_sched_result_with_all_supported_pdus(); + const mac_ul_sched_result& result = result_test.result; + translator.on_new_uplink_scheduler_results(result); + + const fapi::ul_tti_request_message& msg = gateway_spy.ul_tti_request_msg(); + ASSERT_EQ(msg.pdus.size(), MAX_UL_PDUS_PER_SLOT); +} diff --git a/tests/unittests/fapi_adaptor/mac/messages/helpers.cpp b/tests/unittests/fapi_adaptor/mac/messages/helpers.cpp index 34272eb43a..9c0a97b5aa 100644 --- a/tests/unittests/fapi_adaptor/mac/messages/helpers.cpp +++ b/tests/unittests/fapi_adaptor/mac/messages/helpers.cpp @@ -244,6 +244,38 @@ static void add_dl_pdcch_pdus_to_result(mac_dl_sched_result_test_helper& helper) } } +static void add_all_dl_pdcch_pdus_to_result(mac_dl_sched_result_test_helper& helper) +{ + for (unsigned i = 0; i != MAX_DL_PDCCH_PDUS_PER_SLOT; ++i) { + pdcch_dl_information info{ + generate_dci_context(helper.bwp_cfg_pdcch[std::min(i, helper.bwp_cfg_pdcch.size() - 1U)], + helper.coreset_cfg[std::min(i, helper.coreset_cfg.size() - 1U)]), + generate_dci_dl_info()}; + helper.sched_result.dl_pdcchs.push_back(std::move(info)); + } + + // Add the DCIs payload. + for (unsigned i = 0; i != MAX_DL_PDCCH_PDUS_PER_SLOT; ++i) { + helper.result.dl_pdcch_pdus.push_back(generate_dci_payload()); + } +} + +static void add_all_ul_pdcch_pdus_to_result(mac_dl_sched_result_test_helper& helper) +{ + for (unsigned i = 0; i != MAX_UL_PDCCH_PDUS_PER_SLOT; ++i) { + pdcch_ul_information info{ + generate_dci_context(helper.bwp_cfg_pdcch[std::min(i, helper.bwp_cfg_pdcch.size() - 1U)], + helper.coreset_cfg[std::min(i, helper.coreset_cfg.size() - 1U)]), + {}}; + helper.sched_result.ul_pdcchs.push_back(std::move(info)); + } + + // Add the DCIs payload. + for (unsigned i = 0; i != MAX_UL_PDCCH_PDUS_PER_SLOT; ++i) { + helper.result.ul_pdcch_pdus.push_back(generate_dci_payload()); + } +} + static pdsch_information fill_valid_pdsch_information(coreset_configuration& coreset_cfg, bwp_configuration& bwp_config, pdsch_information& info, @@ -398,6 +430,97 @@ mac_dl_sched_result_test_helper unittests::build_valid_mac_dl_sched_result() return helper; } +static csi_rs_info build_valid_csi_pdu(mac_dl_sched_result_test_helper& helper) +{ + csi_rs_info result; + result.bwp_cfg = &helper.bwp_cfg[0]; + result.crbs = {40, 120}; + result.type = csi_rs_type::CSI_RS_ZP; + result.row = 1; + result.freq_domain = bounded_bitset<12, false>(12); + result.symbol0 = 0; + result.symbol1 = 4; + result.cdm_type = csi_rs_cdm_type::no_CDM; + result.freq_density = csi_rs_freq_density_type::one; + result.scrambling_id = 0; + result.power_ctrl_offset = 0; + result.power_ctrl_offset_ss = 0; + + return result; +} + +mac_dl_sched_result_test_helper unittests::build_valid_mac_dl_sched_result_with_all_supported_pdus() +{ + mac_dl_sched_result_test_helper helper; + mac_dl_sched_result& result = helper.result; + + for (unsigned i = 0, e = helper.coreset_cfg.size(); i != e; ++i) { + helper.coreset_cfg[i] = generate_coreset_configuration(); + helper.bwp_cfg[i] = generate_bwp_configuration(); + } + + for (unsigned i = 0; i != MAX_DL_PDCCH_PDUS_PER_SLOT; ++i) { + helper.bwp_cfg_pdcch[i] = {cyclic_prefix::NORMAL, subcarrier_spacing::kHz240, {0 + i, 20 + i}}; + } + + result.slot = slot_point(4, generate_sfn(), generate_slot()); + result.dl_res = &helper.sched_result; + + // Add DL PDCCH PDUs. + add_all_dl_pdcch_pdus_to_result(helper); + + // Add UL PDCCH PDU. + add_all_ul_pdcch_pdus_to_result(helper); + + // Add SIB1 PDU. + helper.sib1 = build_valid_sib1_information_pdu(); + // Fix the BWP and CORESET pointers. + helper.sib1.pdu.pdsch_cfg.bwp_cfg = &helper.sib1.bwp_cfg; + helper.sib1.pdu.pdsch_cfg.coreset_cfg = &helper.sib1.coreset_cfg; + for (unsigned i = 0; i != MAX_SI_PDUS_PER_SLOT; ++i) { + helper.sched_result.bc.sibs.push_back(helper.sib1.pdu); + } + + // Add RAR PDU. + helper.rar = build_valid_rar_information_pdu(); + // Fix the BWP and CORESET pointers. + helper.rar.pdu.pdsch_cfg.bwp_cfg = &helper.rar.bwp_cfg; + helper.rar.pdu.pdsch_cfg.coreset_cfg = &helper.rar.coreset_cfg; + for (unsigned i = 0; i != MAX_RAR_PDUS_PER_SLOT; ++i) { + helper.sched_result.rar_grants.push_back(helper.rar.pdu); + } + + // Add paging PDU. + helper.dl_paging = build_valid_dl_paging_pdu(); + // Fix the BWP and CORESET pointers. + helper.dl_paging.pdu.pdsch_cfg.bwp_cfg = &helper.dl_paging.bwp_cfg; + helper.dl_paging.pdu.pdsch_cfg.coreset_cfg = &helper.dl_paging.coreset_cfg; + for (unsigned i = 0; i != MAX_PAGING_PDUS_PER_SLOT; ++i) { + helper.sched_result.paging_grants.push_back(helper.dl_paging.pdu); + } + + // Add downlink UE PDU. + helper.dl_msg_alloc = build_valid_dl_msg_alloc_pdu(); + // Fix the BWP and CORESET pointers. + helper.dl_msg_alloc.pdu.pdsch_cfg.bwp_cfg = &helper.dl_msg_alloc.bwp_cfg; + helper.dl_msg_alloc.pdu.pdsch_cfg.coreset_cfg = &helper.dl_msg_alloc.coreset_cfg; + for (unsigned i = 0; i != MAX_UE_PDUS_PER_SLOT; ++i) { + helper.sched_result.ue_grants.push_back(helper.dl_msg_alloc.pdu); + } + + // Add CSI PDU. + for (unsigned i = 0; i != MAX_CSI_RS_PDUS_PER_SLOT; ++i) { + helper.sched_result.csi_rs.push_back(build_valid_csi_pdu(helper)); + } + + // Add SSBs. + for (unsigned i = 0; i != MAX_SSB_PER_SLOT; ++i) { + result.ssb_pdus.push_back(build_valid_dl_ssb_pdu()); + } + + return helper; +} + prach_occasion_info unittests::build_valid_prach_occassion() { prach_occasion_info prach; @@ -482,11 +605,11 @@ srs_info_helper unittests::build_valid_srs_pdu() pdu.sequence_id = 4; pdu.bw_index = 2; pdu.tx_comb = tx_comb_size::n2; - pdu.comb_offset = 2; + pdu.comb_offset = 1; pdu.cyclic_shift = 2; pdu.freq_position = 32; pdu.freq_shift = 21; - pdu.freq_hopping = 12; + pdu.freq_hopping = 3; pdu.group_or_seq_hopping = srs_group_or_sequence_hopping::neither; pdu.resource_type = srs_resource_type::aperiodic; pdu.t_srs_period = srs_periodicity::sl8; @@ -544,7 +667,7 @@ pucch_info_test_helper srsran::unittests::build_valid_pucch_format_2_pdu() mac_ul_sched_result_test_helper srsran::unittests::build_valid_mac_ul_sched_result() { - mac_ul_sched_result_test_helper helper; + mac_ul_sched_result_test_helper helper{{}, {}, {}, build_valid_srs_pdu(), {}, {}}; mac_ul_sched_result& result = helper.result; result.slot = slot_point(4, generate_sfn(), generate_slot()); result.ul_res = &helper.sched_result; @@ -568,6 +691,40 @@ mac_ul_sched_result_test_helper srsran::unittests::build_valid_mac_ul_sched_resu return helper; } +mac_ul_sched_result_test_helper unittests::build_valid_mac_ul_sched_result_with_all_supported_pdus() +{ + mac_ul_sched_result_test_helper helper{{}, {}, {}, build_valid_srs_pdu(), {}, {}}; + mac_ul_sched_result& result = helper.result; + result.slot = slot_point(4, generate_sfn(), generate_slot()); + result.ul_res = &helper.sched_result; + + // Add PUCCH PDUs. + for (unsigned i = 0; i != MAX_PUCCH_PDUS_PER_SLOT; ++i) { + helper.pucch_f1 = build_valid_pucch_format_1_pdu(); + helper.pucch_f1.info.bwp_cfg = &helper.pucch_f1.bwp_cfg; + helper.sched_result.pucchs.push_back(helper.pucch_f1.info); + } + + // Add PUSCH PDU. + for (unsigned i = 0; i != MAX_PUSCH_PDUS_PER_SLOT; ++i) { + helper.pusch = build_valid_pusch_pdu(); + helper.pusch.info.pusch_cfg.bwp_cfg = &helper.pusch.bwp_cfg; + helper.sched_result.puschs.push_back(helper.pusch.info); + } + + // Add PRACH. + for (unsigned i = 0; i != MAX_PRACH_OCCASIONS_PER_SLOT; ++i) { + helper.sched_result.prachs.push_back(build_valid_prach_occassion()); + } + + // Add SRS. + for (unsigned i = 0; i != MAX_SRS_PDUS_PER_SLOT; ++i) { + helper.sched_result.srss.push_back(helper.srs.pdu); + } + + return helper; +} + mac_dl_data_result srsran::unittests::build_valid_mac_data_result() { mac_dl_data_result result; @@ -576,3 +733,26 @@ mac_dl_data_result srsran::unittests::build_valid_mac_data_result() return result; } + +mac_dl_data_result unittests::build_valid_mac_data_result_with_all_supported_pdu() +{ + mac_dl_data_result result; + + for (unsigned i = 0; i != MAX_SI_PDUS_PER_SLOT; ++i) { + result.si_pdus.push_back({1, {}}); + } + + for (unsigned i = 0; i != MAX_RAR_PDUS_PER_SLOT; ++i) { + result.rar_pdus.push_back({1, {}}); + } + + for (unsigned i = 0; i != MAX_UE_PDUS_PER_SLOT; ++i) { + result.ue_pdus.push_back({1, {}}); + } + + for (unsigned i = 0; i != MAX_PAGING_PDUS_PER_SLOT; ++i) { + result.paging_pdus.push_back({1, {}}); + } + + return result; +} diff --git a/tests/unittests/fapi_adaptor/mac/messages/helpers.h b/tests/unittests/fapi_adaptor/mac/messages/helpers.h index 6d39f48746..35f5f3c95f 100644 --- a/tests/unittests/fapi_adaptor/mac/messages/helpers.h +++ b/tests/unittests/fapi_adaptor/mac/messages/helpers.h @@ -60,16 +60,23 @@ dl_ssb_pdu build_valid_dl_ssb_pdu(); /// Helper struct to manage the pointer life cycle of a MAC DL scheduling result. struct mac_dl_sched_result_test_helper { - std::array bwp_cfg; - std::array coreset_cfg; - sib_information_test_helper sib1; - dl_sched_result sched_result; - mac_dl_sched_result result; + std::array bwp_cfg; + std::array bwp_cfg_pdcch; + std::array coreset_cfg; + sib_information_test_helper sib1; + rar_information_test_helper rar; + dl_paging_allocation_test_helper dl_paging; + dl_msg_allocation_test_helper dl_msg_alloc; + dl_sched_result sched_result; + mac_dl_sched_result result; }; /// Builds and returns a valid MAC data result. mac_dl_data_result build_valid_mac_data_result(); +/// Builds and returns a valid MAC data result. +mac_dl_data_result build_valid_mac_data_result_with_all_supported_pdu(); + /// Builds and returns a valid PRACH occassion. prach_occasion_info build_valid_prach_occassion(); @@ -105,11 +112,15 @@ pucch_info_test_helper build_valid_pucch_format_2_pdu(); /// Builds and returns a valid MAC DL sched result. mac_dl_sched_result_test_helper build_valid_mac_dl_sched_result(); +/// Builds and returns a valid MAC DL sched result with all the PDUs filled. +mac_dl_sched_result_test_helper build_valid_mac_dl_sched_result_with_all_supported_pdus(); + /// Helper struct to manage the pointer life cycle of a MAC UL scheduling result. struct mac_ul_sched_result_test_helper { pucch_info_test_helper pucch_f1; pucch_info_test_helper pucch_f2; ul_sched_info_test_helper pusch; + srs_info_helper srs; ul_sched_result sched_result; mac_ul_sched_result result; }; @@ -117,5 +128,8 @@ struct mac_ul_sched_result_test_helper { /// Builds and returns a valid MAC UL sched result. mac_ul_sched_result_test_helper build_valid_mac_ul_sched_result(); +/// Builds and returns a valid MAC UL sched result with all PDUs filled. +mac_ul_sched_result_test_helper build_valid_mac_ul_sched_result_with_all_supported_pdus(); + } // namespace unittests } // namespace srsran From 133e3ede92e2dc1f5bb135e0c59ba9e8cfc967a1 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 6 Nov 2024 12:25:28 +0100 Subject: [PATCH 05/26] srsvec: add more SIMD functions srsvec: fix compilation --- include/srsran/srsvec/simd.h | 80 ++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/include/srsran/srsvec/simd.h b/include/srsran/srsvec/simd.h index 19f2f12b4c..55f6543085 100644 --- a/include/srsran/srsvec/simd.h +++ b/include/srsran/srsvec/simd.h @@ -394,6 +394,20 @@ inline simd_f_t srsran_simd_f_sub(simd_f_t a, simd_f_t b) #endif /* __AVX512F__ */ } +inline simd_f_t srsran_simd_f_precise_rcp(simd_f_t x) +{ + // Initial approximation of 1/x + simd_f_t approx = srsran_simd_f_rcp(x); + + // Refine using one Newton-Raphson iteration. + simd_f_t mult = srsran_simd_f_mul(x, approx); + simd_f_t two = srsran_simd_f_set1(2.0f); + simd_f_t correction = srsran_simd_f_sub(two, mult); + simd_f_t refined = srsran_simd_f_mul(approx, correction); + + return refined; +} + inline simd_f_t srsran_simd_f_add(simd_f_t a, simd_f_t b) { #ifdef __AVX512F__ @@ -1321,6 +1335,53 @@ inline void srsran_simd_cf_fprintf(std::FILE* stream, simd_cf_t a) std::fprintf(stream, "];\n"); } + +/// Adds two complex SIMD registers. +inline simd_cf_t operator+(simd_cf_t left, simd_cf_t right) +{ + return srsran_simd_cf_add(left, right); +} + +/// Multiplies two complex SIMD registers. +inline simd_cf_t operator*(simd_cf_t left, simd_cf_t right) +{ + return srsran_simd_cf_prod(left, right); +} + +/// Multiplies two complex SIMD registers. +inline simd_cf_t& operator*=(simd_cf_t& left, const simd_cf_t& right) +{ + left = srsran_simd_cf_prod(left, right); + return left; +} + +/// Multiplies a complex SIMD register by a real literal. +inline simd_cf_t& operator*=(simd_cf_t& left, float right) +{ + left = srsran_simd_cf_mul(left, srsran_simd_f_set1(right)); + return left; +} + +/// Subtract two complex SIMD registers. +inline simd_cf_t& operator-=(simd_cf_t& left, const simd_cf_t& right) +{ + left = srsran_simd_cf_sub(left, right); + return left; +} + +/// Add two complex SIMD registers. +inline simd_cf_t& operator+=(simd_cf_t& left, const simd_cf_t& right) +{ + left = srsran_simd_cf_add(left, right); + return left; +} + +/// Negate a complex SIMD register. +inline simd_cf_t operator-(simd_cf_t value) +{ + return srsran_simd_cf_neg(value); +} + #endif /* SRSRAN_SIMD_CF_SIZE */ #if SRSRAN_SIMD_I_SIZE @@ -1459,6 +1520,25 @@ inline simd_i_t srsran_simd_i_and(simd_i_t a, simd_i_t b) #endif /* __AVX512F__ */ } +inline simd_sel_t srsran_simd_sel_set_ones() +{ +#ifdef __AVX512F__ + return ~static_cast(0); +#else /* __AVX512F__ */ +#ifdef __AVX2__ + return _mm256_castsi256_ps(_mm256_set1_epi32(0xFFFFFFFF)); +#else +#ifdef __SSE4_1__ + return _mm_castsi256_ps(_mm_set1_epi32(0xFFFFFFFF)); +#else +#ifdef __ARM_NEON + return vdupq_n_s32(-1); +#endif /* __ARM_NEON */ +#endif /* __SSE4_1__ */ +#endif /* __AVX2__ */ +#endif /* __AVX512F__ */ +} + inline simd_sel_t srsran_simd_sel_and(simd_sel_t a, simd_sel_t b) { #ifdef __AVX512F__ From 84cfbffc06becf1d41a10f5e26e99dde5a056065 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 6 Nov 2024 17:51:50 +0100 Subject: [PATCH 06/26] phy: add more equalizer topologies Fix format --- include/srsran/srsvec/simd.h | 5 +- .../channel_equalizer_generic_impl.cpp | 96 ++++++++++++++++--- .../channel_equalizer_generic_impl.h | 48 ++++++++++ lib/phy/upper/equalization/equalize_zf_3x4.h | 26 ----- lib/phy/upper/equalization/equalize_zf_4x4.h | 26 ----- 5 files changed, 132 insertions(+), 69 deletions(-) delete mode 100644 lib/phy/upper/equalization/equalize_zf_3x4.h delete mode 100644 lib/phy/upper/equalization/equalize_zf_4x4.h diff --git a/include/srsran/srsvec/simd.h b/include/srsran/srsvec/simd.h index 55f6543085..cbba15661a 100644 --- a/include/srsran/srsvec/simd.h +++ b/include/srsran/srsvec/simd.h @@ -1335,7 +1335,6 @@ inline void srsran_simd_cf_fprintf(std::FILE* stream, simd_cf_t a) std::fprintf(stream, "];\n"); } - /// Adds two complex SIMD registers. inline simd_cf_t operator+(simd_cf_t left, simd_cf_t right) { @@ -1526,10 +1525,10 @@ inline simd_sel_t srsran_simd_sel_set_ones() return ~static_cast(0); #else /* __AVX512F__ */ #ifdef __AVX2__ - return _mm256_castsi256_ps(_mm256_set1_epi32(0xFFFFFFFF)); + return _mm256_castsi256_ps(_mm256_set1_epi32(0xffffffff)); #else #ifdef __SSE4_1__ - return _mm_castsi256_ps(_mm_set1_epi32(0xFFFFFFFF)); + return _mm_castsi256_ps(_mm_set1_epi32(0xffffffff)); #else #ifdef __ARM_NEON return vdupq_n_s32(-1); diff --git a/lib/phy/upper/equalization/channel_equalizer_generic_impl.cpp b/lib/phy/upper/equalization/channel_equalizer_generic_impl.cpp index ae7e0514dd..f1fbb118e5 100644 --- a/lib/phy/upper/equalization/channel_equalizer_generic_impl.cpp +++ b/lib/phy/upper/equalization/channel_equalizer_generic_impl.cpp @@ -15,8 +15,6 @@ #include "equalize_mmse_1xn.h" #include "equalize_zf_1xn.h" #include "equalize_zf_2xn.h" -#include "equalize_zf_3x4.h" -#include "equalize_zf_4x4.h" #include "srsran/adt/interval.h" #include "srsran/phy/support/re_buffer.h" #include "srsran/phy/upper/equalization/modular_ch_est_list.h" @@ -211,26 +209,72 @@ void equalize_mmse_single_tx_layer<1>(unsigned /**/, equalize_mmse_1xn<1>(eq_symbols, eq_noise_vars, ch_symbols, ch_estimates, noise_var, tx_scaling); } -SRSRAN_WEAK_SYMB void srsran::equalize_zf_3x4(span /* eq_symbols */, - span /* noise_vars */, - const re_buffer_reader& /* ch_symbols */, - const channel_equalizer::ch_est_list& /* ch_estimates */, - float /* noise_var_est */, - float /* tx_scaling */) +SRSRAN_WEAK_SYMB void +channel_equalizer_generic_impl::equalize_zf_3x4(span /* eq_symbols */, + span /* noise_vars */, + const re_buffer_reader& /* ch_symbols */, + const channel_equalizer::ch_est_list& /* ch_estimates */, + float /* noise_var_est */, + float /* tx_scaling */) { srsran_assertion_failure("Equalizer not implemented for 3x4 ZF algorithm."); } -SRSRAN_WEAK_SYMB void srsran::equalize_zf_4x4(span /* eq_symbols */, - span /* noise_vars */, - const re_buffer_reader& /* ch_symbols */, - const channel_equalizer::ch_est_list& /* ch_estimates */, - float /* noise_var_est */, - float /* tx_scaling */) +SRSRAN_WEAK_SYMB void +channel_equalizer_generic_impl::equalize_zf_4x4(span /* eq_symbols */, + span /* noise_vars */, + const re_buffer_reader& /* ch_symbols */, + const channel_equalizer::ch_est_list& /* ch_estimates */, + float /* noise_var_est */, + float /* tx_scaling */) { srsran_assertion_failure("Equalizer not implemented for 4x4 ZF algorithm."); } +SRSRAN_WEAK_SYMB void +channel_equalizer_generic_impl::equalize_mmse_2x2(span /* eq_symbols */, + span /* noise_vars */, + const re_buffer_reader& /* ch_symbols */, + const channel_equalizer::ch_est_list& /* ch_estimates */, + float /* noise_var_est */, + float /* tx_scaling */) +{ + srsran_assertion_failure("Equalizer not implemented for 2x2 MMSE algorithm."); +} + +SRSRAN_WEAK_SYMB void +channel_equalizer_generic_impl::equalize_mmse_2x4(span /* eq_symbols */, + span /* noise_vars */, + const re_buffer_reader& /* ch_symbols */, + const channel_equalizer::ch_est_list& /* ch_estimates */, + float /* noise_var_est */, + float /* tx_scaling */) +{ + srsran_assertion_failure("Equalizer not implemented for 2x4 MMSE algorithm."); +} + +SRSRAN_WEAK_SYMB void +channel_equalizer_generic_impl::equalize_mmse_3x4(span /* eq_symbols */, + span /* noise_vars */, + const re_buffer_reader& /* ch_symbols */, + const channel_equalizer::ch_est_list& /* ch_estimates */, + float /* noise_var_est */, + float /* tx_scaling */) +{ + srsran_assertion_failure("Equalizer not implemented for 3x4 MMSE algorithm."); +} + +SRSRAN_WEAK_SYMB void +channel_equalizer_generic_impl::equalize_mmse_4x4(span /* eq_symbols */, + span /* noise_vars */, + const re_buffer_reader& /* ch_symbols */, + const channel_equalizer::ch_est_list& /* ch_estimates */, + float /* noise_var_est */, + float /* tx_scaling */) +{ + srsran_assertion_failure("Equalizer not implemented for 4x4 MMSE algorithm."); +} + bool channel_equalizer_generic_impl::is_supported(unsigned nof_ports, unsigned nof_layers) { return is_supported(type, nof_ports, nof_layers); @@ -297,6 +341,30 @@ void channel_equalizer_generic_impl::equalize(span e nof_rx_ports, eq_symbols, eq_noise_vars, ch_symbols, ch_estimates, noise_var_estimates, tx_scaling); return; } + + // Two transmit layers and two receive ports. + if ((nof_rx_ports == 2) && (nof_tx_layers == 2)) { + equalize_mmse_2x2(eq_symbols, eq_noise_vars, ch_symbols, ch_estimates, noise_var, tx_scaling); + return; + } + + // Two transmit layers and four receive ports. + if ((nof_rx_ports == 4) && (nof_tx_layers == 2)) { + equalize_mmse_2x4(eq_symbols, eq_noise_vars, ch_symbols, ch_estimates, noise_var, tx_scaling); + return; + } + + // Three transmit layers and four receive ports. + if ((nof_rx_ports == 4) && (nof_tx_layers == 3)) { + equalize_mmse_3x4(eq_symbols, eq_noise_vars, ch_symbols, ch_estimates, noise_var, tx_scaling); + return; + } + + // Four transmit layers and four receive ports. + if ((nof_rx_ports == 4) && (nof_tx_layers == 4)) { + equalize_mmse_4x4(eq_symbols, eq_noise_vars, ch_symbols, ch_estimates, noise_var, tx_scaling); + return; + } } srsran_assertion_failure( diff --git a/lib/phy/upper/equalization/channel_equalizer_generic_impl.h b/lib/phy/upper/equalization/channel_equalizer_generic_impl.h index 1030d11a44..7e86277436 100644 --- a/lib/phy/upper/equalization/channel_equalizer_generic_impl.h +++ b/lib/phy/upper/equalization/channel_equalizer_generic_impl.h @@ -43,6 +43,54 @@ class channel_equalizer_generic_impl : public channel_equalizer /// Determines whether a combination of the algorithm type, number of layers, and number of ports is supported. static bool is_supported(channel_equalizer_algorithm_type algorithm, unsigned nof_ports, unsigned nof_layers); + /// ZF Equalization function for 3 layers and 4 ports. + static void equalize_zf_3x4(span eq_symbols, + span noise_vars, + const re_buffer_reader& ch_symbols, + const channel_equalizer::ch_est_list& ch_estimates_, + float noise_var_est, + float tx_scaling); + + /// ZF Equalization function for 4 layers and 4 ports. + static void equalize_zf_4x4(span eq_symbols, + span noise_vars, + const re_buffer_reader& ch_symbols, + const channel_equalizer::ch_est_list& ch_estimates_, + float noise_var_est, + float tx_scaling); + + /// Linear MMSE Equalization function for 2 layers and 2 ports. + static void equalize_mmse_2x2(span eq_symbols, + span noise_vars, + const re_buffer_reader& ch_symbols, + const channel_equalizer::ch_est_list& ch_estimates_, + float noise_var_est, + float tx_scaling); + + /// Linear MMSE Equalization function for 2 layers and 4 ports. + static void equalize_mmse_2x4(span eq_symbols, + span noise_vars, + const re_buffer_reader& ch_symbols, + const channel_equalizer::ch_est_list& ch_estimates_, + float noise_var_est, + float tx_scaling); + + /// Linear MMSE Equalization function for 3 layers and 4 ports. + static void equalize_mmse_3x4(span eq_symbols, + span noise_vars, + const re_buffer_reader& ch_symbols, + const channel_equalizer::ch_est_list& ch_estimates_, + float noise_var_est, + float tx_scaling); + + /// Linear MMSE Equalization function for 4 layers and 4 ports. + static void equalize_mmse_4x4(span eq_symbols, + span noise_vars, + const re_buffer_reader& ch_symbols, + const channel_equalizer::ch_est_list& ch_estimates_, + float noise_var_est, + float tx_scaling); + channel_equalizer_algorithm_type type; }; diff --git a/lib/phy/upper/equalization/equalize_zf_3x4.h b/lib/phy/upper/equalization/equalize_zf_3x4.h deleted file mode 100644 index 5a0c941841..0000000000 --- a/lib/phy/upper/equalization/equalize_zf_3x4.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#pragma once - -#include "srsran/adt/span.h" -#include "srsran/phy/support/re_buffer.h" -#include "srsran/phy/upper/equalization/channel_equalizer.h" - -namespace srsran { - -void equalize_zf_3x4(span eq_symbols, - span noise_vars, - const re_buffer_reader& ch_symbols, - const channel_equalizer::ch_est_list& ch_estimates_, - float noise_var_est, - float tx_scaling); - -} // namespace srsran diff --git a/lib/phy/upper/equalization/equalize_zf_4x4.h b/lib/phy/upper/equalization/equalize_zf_4x4.h deleted file mode 100644 index 35307eb917..0000000000 --- a/lib/phy/upper/equalization/equalize_zf_4x4.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#pragma once - -#include "srsran/adt/span.h" -#include "srsran/phy/support/re_buffer.h" -#include "srsran/phy/upper/equalization/channel_equalizer.h" - -namespace srsran { - -void equalize_zf_4x4(span eq_symbols, - span noise_vars, - const re_buffer_reader& ch_symbols, - const channel_equalizer::ch_est_list& ch_estimates_, - float noise_var_est, - float tx_scaling); - -} // namespace srsran From a56e4b92bfd3e74e74143b717d81aaa4d3fbf8fa Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 11 Nov 2024 12:53:41 +0100 Subject: [PATCH 07/26] simd: removed unused function --- include/srsran/srsvec/simd.h | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/include/srsran/srsvec/simd.h b/include/srsran/srsvec/simd.h index cbba15661a..b98811f78d 100644 --- a/include/srsran/srsvec/simd.h +++ b/include/srsran/srsvec/simd.h @@ -1519,25 +1519,6 @@ inline simd_i_t srsran_simd_i_and(simd_i_t a, simd_i_t b) #endif /* __AVX512F__ */ } -inline simd_sel_t srsran_simd_sel_set_ones() -{ -#ifdef __AVX512F__ - return ~static_cast(0); -#else /* __AVX512F__ */ -#ifdef __AVX2__ - return _mm256_castsi256_ps(_mm256_set1_epi32(0xffffffff)); -#else -#ifdef __SSE4_1__ - return _mm_castsi256_ps(_mm_set1_epi32(0xffffffff)); -#else -#ifdef __ARM_NEON - return vdupq_n_s32(-1); -#endif /* __ARM_NEON */ -#endif /* __SSE4_1__ */ -#endif /* __AVX2__ */ -#endif /* __AVX512F__ */ -} - inline simd_sel_t srsran_simd_sel_and(simd_sel_t a, simd_sel_t b) { #ifdef __AVX512F__ From bcbc3c07f8d51437ef53a27d491776c7b9ba0a6e Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 7 Nov 2024 13:22:31 +0100 Subject: [PATCH 08/26] phy: correct noise variance with transform precoding phy: integrate noise variance processing into the transform precoder phy: remove meaningless doc paragraph --- .../transform_precoding/transform_precoder.h | 8 ++ .../transform_precoder_dft_impl.cpp | 27 ++++ .../transform_precoder_dft_impl.h | 3 + .../pusch/pusch_demodulator_impl.cpp | 1 + .../transform_precoder_test_data.h | 116 +++++++++--------- .../transform_precoder_test_data.tar.gz | 4 +- .../transform_precoder_vectortest.cpp | 59 ++++++--- .../pusch/pusch_demodulator_test_data.h | 2 +- .../pusch/pusch_demodulator_test_data.tar.gz | 4 +- 9 files changed, 145 insertions(+), 79 deletions(-) diff --git a/include/srsran/phy/generic_functions/transform_precoding/transform_precoder.h b/include/srsran/phy/generic_functions/transform_precoding/transform_precoder.h index bea47c040c..1440a794cb 100644 --- a/include/srsran/phy/generic_functions/transform_precoding/transform_precoder.h +++ b/include/srsran/phy/generic_functions/transform_precoding/transform_precoder.h @@ -41,6 +41,14 @@ class transform_precoder /// \remark An assertion is triggered if the number of RB to deprecode is invalid. /// \remark An assertion is triggered if the number of RB exceeds the maximum initialized number of RB. virtual void deprecode_ofdm_symbol(span out, span in) = 0; + + /// \brief Calculates the resultant noise variance after reverting the transform precoding operation. + /// + /// Noise variances that are NaN, infinite or negative are not taken into account neither for the calculation of mean + /// nor overwriting. + /// \param[out] out Resultant noise variance. + /// \param[in] in Input noise variance for each resource element. + virtual void deprecode_ofdm_symbol_noise(span out, span in) = 0; }; } // namespace srsran diff --git a/lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.cpp b/lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.cpp index 1a6d2c1b47..bc81717e78 100644 --- a/lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.cpp +++ b/lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.cpp @@ -13,6 +13,7 @@ #include "srsran/ran/transform_precoding/transform_precoding_helpers.h" #include "srsran/srsvec/copy.h" #include "srsran/srsvec/sc_prod.h" +#include using namespace srsran; @@ -43,3 +44,29 @@ void transform_precoder_dft_impl::deprecode_ofdm_symbol(span x, span out, span in) +{ + // Lambda to check if a noise variance value is valid. + auto is_valid_noise_variance = [](float value) { return (value > 0.0F) && !std::isnan(value) && !std::isinf(value); }; + + // Accumulate all the valid noise variances. + unsigned count = 0; + float eq_noise_vars_mean = + std::accumulate(in.begin(), in.end(), 0.0F, [&count, &is_valid_noise_variance](float acc, float value) { + // Skip value if is negative, zero, nan or infinite. + if (is_valid_noise_variance(value)) { + ++count; + return acc + value; + } + return acc; + }); + if (count != 0) { + eq_noise_vars_mean /= count; + } + + // Write the mean channel estimates. + std::transform(in.begin(), in.end(), out.begin(), [&eq_noise_vars_mean, &is_valid_noise_variance](float value) { + return is_valid_noise_variance(value) ? eq_noise_vars_mean : value; + }); +} diff --git a/lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.h b/lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.h index 0fa9db8501..f8b035c205 100644 --- a/lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.h +++ b/lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.h @@ -49,6 +49,9 @@ class transform_precoder_dft_impl : public transform_precoder // See interface for documentation. void deprecode_ofdm_symbol(span out, span in) override; + // See interface for documentation. + void deprecode_ofdm_symbol_noise(span out, span in) override; + private: /// Collection of valid DFT processors. collection_dft_processors dft_processors; diff --git a/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.cpp b/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.cpp index a0ccb09bfd..9c82824c18 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.cpp +++ b/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.cpp @@ -188,6 +188,7 @@ void pusch_demodulator_impl::demodulate(pusch_codeword_buffer& codeword_buf "Transform precoding is only possible with one layer (i.e. {}).", config.nof_tx_layers); precoder->deprecode_ofdm_symbol(eq_re, eq_re); + precoder->deprecode_ofdm_symbol_noise(eq_noise_vars, eq_noise_vars); } // Estimate post equalization Signal-to-Interference-plus-Noise Ratio. diff --git a/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.h b/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.h index d54d153cae..1f8226264d 100644 --- a/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.h +++ b/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 19-07-2024 (seed 0): +// This file was generated using the following MATLAB class on 08-11-2024 (seed 0): // + "srsTransformPrecoderUnittest.m" #include "srsran/adt/complex.h" @@ -19,66 +19,68 @@ namespace srsran { struct test_case_t { - unsigned M_rb; - file_vector deprecode_input; - file_vector deprecode_output; + unsigned M_rb; + file_vector deprecode_data_input; + file_vector deprecode_noise_input; + file_vector deprecode_data_output; + file_vector deprecode_noise_output; }; static const std::vector transform_precoder_test_data = { // clang-format off - {1, {"test_data/transform_precoder_test_input0.dat"}, {"test_data/transform_precoder_test_output0.dat"}}, - {2, {"test_data/transform_precoder_test_input1.dat"}, {"test_data/transform_precoder_test_output1.dat"}}, - {3, {"test_data/transform_precoder_test_input2.dat"}, {"test_data/transform_precoder_test_output2.dat"}}, - {4, {"test_data/transform_precoder_test_input3.dat"}, {"test_data/transform_precoder_test_output3.dat"}}, - {5, {"test_data/transform_precoder_test_input4.dat"}, {"test_data/transform_precoder_test_output4.dat"}}, - {6, {"test_data/transform_precoder_test_input5.dat"}, {"test_data/transform_precoder_test_output5.dat"}}, - {8, {"test_data/transform_precoder_test_input6.dat"}, {"test_data/transform_precoder_test_output6.dat"}}, - {9, {"test_data/transform_precoder_test_input7.dat"}, {"test_data/transform_precoder_test_output7.dat"}}, - {10, {"test_data/transform_precoder_test_input8.dat"}, {"test_data/transform_precoder_test_output8.dat"}}, - {12, {"test_data/transform_precoder_test_input9.dat"}, {"test_data/transform_precoder_test_output9.dat"}}, - {15, {"test_data/transform_precoder_test_input10.dat"}, {"test_data/transform_precoder_test_output10.dat"}}, - {16, {"test_data/transform_precoder_test_input11.dat"}, {"test_data/transform_precoder_test_output11.dat"}}, - {18, {"test_data/transform_precoder_test_input12.dat"}, {"test_data/transform_precoder_test_output12.dat"}}, - {20, {"test_data/transform_precoder_test_input13.dat"}, {"test_data/transform_precoder_test_output13.dat"}}, - {24, {"test_data/transform_precoder_test_input14.dat"}, {"test_data/transform_precoder_test_output14.dat"}}, - {25, {"test_data/transform_precoder_test_input15.dat"}, {"test_data/transform_precoder_test_output15.dat"}}, - {27, {"test_data/transform_precoder_test_input16.dat"}, {"test_data/transform_precoder_test_output16.dat"}}, - {30, {"test_data/transform_precoder_test_input17.dat"}, {"test_data/transform_precoder_test_output17.dat"}}, - {32, {"test_data/transform_precoder_test_input18.dat"}, {"test_data/transform_precoder_test_output18.dat"}}, - {36, {"test_data/transform_precoder_test_input19.dat"}, {"test_data/transform_precoder_test_output19.dat"}}, - {40, {"test_data/transform_precoder_test_input20.dat"}, {"test_data/transform_precoder_test_output20.dat"}}, - {45, {"test_data/transform_precoder_test_input21.dat"}, {"test_data/transform_precoder_test_output21.dat"}}, - {48, {"test_data/transform_precoder_test_input22.dat"}, {"test_data/transform_precoder_test_output22.dat"}}, - {50, {"test_data/transform_precoder_test_input23.dat"}, {"test_data/transform_precoder_test_output23.dat"}}, - {54, {"test_data/transform_precoder_test_input24.dat"}, {"test_data/transform_precoder_test_output24.dat"}}, - {60, {"test_data/transform_precoder_test_input25.dat"}, {"test_data/transform_precoder_test_output25.dat"}}, - {64, {"test_data/transform_precoder_test_input26.dat"}, {"test_data/transform_precoder_test_output26.dat"}}, - {72, {"test_data/transform_precoder_test_input27.dat"}, {"test_data/transform_precoder_test_output27.dat"}}, - {75, {"test_data/transform_precoder_test_input28.dat"}, {"test_data/transform_precoder_test_output28.dat"}}, - {80, {"test_data/transform_precoder_test_input29.dat"}, {"test_data/transform_precoder_test_output29.dat"}}, - {81, {"test_data/transform_precoder_test_input30.dat"}, {"test_data/transform_precoder_test_output30.dat"}}, - {90, {"test_data/transform_precoder_test_input31.dat"}, {"test_data/transform_precoder_test_output31.dat"}}, - {96, {"test_data/transform_precoder_test_input32.dat"}, {"test_data/transform_precoder_test_output32.dat"}}, - {100, {"test_data/transform_precoder_test_input33.dat"}, {"test_data/transform_precoder_test_output33.dat"}}, - {108, {"test_data/transform_precoder_test_input34.dat"}, {"test_data/transform_precoder_test_output34.dat"}}, - {120, {"test_data/transform_precoder_test_input35.dat"}, {"test_data/transform_precoder_test_output35.dat"}}, - {125, {"test_data/transform_precoder_test_input36.dat"}, {"test_data/transform_precoder_test_output36.dat"}}, - {128, {"test_data/transform_precoder_test_input37.dat"}, {"test_data/transform_precoder_test_output37.dat"}}, - {135, {"test_data/transform_precoder_test_input38.dat"}, {"test_data/transform_precoder_test_output38.dat"}}, - {144, {"test_data/transform_precoder_test_input39.dat"}, {"test_data/transform_precoder_test_output39.dat"}}, - {150, {"test_data/transform_precoder_test_input40.dat"}, {"test_data/transform_precoder_test_output40.dat"}}, - {160, {"test_data/transform_precoder_test_input41.dat"}, {"test_data/transform_precoder_test_output41.dat"}}, - {162, {"test_data/transform_precoder_test_input42.dat"}, {"test_data/transform_precoder_test_output42.dat"}}, - {180, {"test_data/transform_precoder_test_input43.dat"}, {"test_data/transform_precoder_test_output43.dat"}}, - {192, {"test_data/transform_precoder_test_input44.dat"}, {"test_data/transform_precoder_test_output44.dat"}}, - {200, {"test_data/transform_precoder_test_input45.dat"}, {"test_data/transform_precoder_test_output45.dat"}}, - {216, {"test_data/transform_precoder_test_input46.dat"}, {"test_data/transform_precoder_test_output46.dat"}}, - {225, {"test_data/transform_precoder_test_input47.dat"}, {"test_data/transform_precoder_test_output47.dat"}}, - {240, {"test_data/transform_precoder_test_input48.dat"}, {"test_data/transform_precoder_test_output48.dat"}}, - {243, {"test_data/transform_precoder_test_input49.dat"}, {"test_data/transform_precoder_test_output49.dat"}}, - {250, {"test_data/transform_precoder_test_input50.dat"}, {"test_data/transform_precoder_test_output50.dat"}}, - {256, {"test_data/transform_precoder_test_input51.dat"}, {"test_data/transform_precoder_test_output51.dat"}}, - {270, {"test_data/transform_precoder_test_input52.dat"}, {"test_data/transform_precoder_test_output52.dat"}}, + {1, {"test_data/transform_precoder_test_input_data0.dat"}, {"test_data/transform_precoder_test_input_noise0.dat"}, {"test_data/transform_precoder_test_output_data0.dat"}, {"test_data/transform_precoder_test_output_noise0.dat"}}, + {2, {"test_data/transform_precoder_test_input_data2.dat"}, {"test_data/transform_precoder_test_input_noise2.dat"}, {"test_data/transform_precoder_test_output_data2.dat"}, {"test_data/transform_precoder_test_output_noise2.dat"}}, + {3, {"test_data/transform_precoder_test_input_data4.dat"}, {"test_data/transform_precoder_test_input_noise4.dat"}, {"test_data/transform_precoder_test_output_data4.dat"}, {"test_data/transform_precoder_test_output_noise4.dat"}}, + {4, {"test_data/transform_precoder_test_input_data6.dat"}, {"test_data/transform_precoder_test_input_noise6.dat"}, {"test_data/transform_precoder_test_output_data6.dat"}, {"test_data/transform_precoder_test_output_noise6.dat"}}, + {5, {"test_data/transform_precoder_test_input_data8.dat"}, {"test_data/transform_precoder_test_input_noise8.dat"}, {"test_data/transform_precoder_test_output_data8.dat"}, {"test_data/transform_precoder_test_output_noise8.dat"}}, + {6, {"test_data/transform_precoder_test_input_data10.dat"}, {"test_data/transform_precoder_test_input_noise10.dat"}, {"test_data/transform_precoder_test_output_data10.dat"}, {"test_data/transform_precoder_test_output_noise10.dat"}}, + {8, {"test_data/transform_precoder_test_input_data12.dat"}, {"test_data/transform_precoder_test_input_noise12.dat"}, {"test_data/transform_precoder_test_output_data12.dat"}, {"test_data/transform_precoder_test_output_noise12.dat"}}, + {9, {"test_data/transform_precoder_test_input_data14.dat"}, {"test_data/transform_precoder_test_input_noise14.dat"}, {"test_data/transform_precoder_test_output_data14.dat"}, {"test_data/transform_precoder_test_output_noise14.dat"}}, + {10, {"test_data/transform_precoder_test_input_data16.dat"}, {"test_data/transform_precoder_test_input_noise16.dat"}, {"test_data/transform_precoder_test_output_data16.dat"}, {"test_data/transform_precoder_test_output_noise16.dat"}}, + {12, {"test_data/transform_precoder_test_input_data18.dat"}, {"test_data/transform_precoder_test_input_noise18.dat"}, {"test_data/transform_precoder_test_output_data18.dat"}, {"test_data/transform_precoder_test_output_noise18.dat"}}, + {15, {"test_data/transform_precoder_test_input_data20.dat"}, {"test_data/transform_precoder_test_input_noise20.dat"}, {"test_data/transform_precoder_test_output_data20.dat"}, {"test_data/transform_precoder_test_output_noise20.dat"}}, + {16, {"test_data/transform_precoder_test_input_data22.dat"}, {"test_data/transform_precoder_test_input_noise22.dat"}, {"test_data/transform_precoder_test_output_data22.dat"}, {"test_data/transform_precoder_test_output_noise22.dat"}}, + {18, {"test_data/transform_precoder_test_input_data24.dat"}, {"test_data/transform_precoder_test_input_noise24.dat"}, {"test_data/transform_precoder_test_output_data24.dat"}, {"test_data/transform_precoder_test_output_noise24.dat"}}, + {20, {"test_data/transform_precoder_test_input_data26.dat"}, {"test_data/transform_precoder_test_input_noise26.dat"}, {"test_data/transform_precoder_test_output_data26.dat"}, {"test_data/transform_precoder_test_output_noise26.dat"}}, + {24, {"test_data/transform_precoder_test_input_data28.dat"}, {"test_data/transform_precoder_test_input_noise28.dat"}, {"test_data/transform_precoder_test_output_data28.dat"}, {"test_data/transform_precoder_test_output_noise28.dat"}}, + {25, {"test_data/transform_precoder_test_input_data30.dat"}, {"test_data/transform_precoder_test_input_noise30.dat"}, {"test_data/transform_precoder_test_output_data30.dat"}, {"test_data/transform_precoder_test_output_noise30.dat"}}, + {27, {"test_data/transform_precoder_test_input_data32.dat"}, {"test_data/transform_precoder_test_input_noise32.dat"}, {"test_data/transform_precoder_test_output_data32.dat"}, {"test_data/transform_precoder_test_output_noise32.dat"}}, + {30, {"test_data/transform_precoder_test_input_data34.dat"}, {"test_data/transform_precoder_test_input_noise34.dat"}, {"test_data/transform_precoder_test_output_data34.dat"}, {"test_data/transform_precoder_test_output_noise34.dat"}}, + {32, {"test_data/transform_precoder_test_input_data36.dat"}, {"test_data/transform_precoder_test_input_noise36.dat"}, {"test_data/transform_precoder_test_output_data36.dat"}, {"test_data/transform_precoder_test_output_noise36.dat"}}, + {36, {"test_data/transform_precoder_test_input_data38.dat"}, {"test_data/transform_precoder_test_input_noise38.dat"}, {"test_data/transform_precoder_test_output_data38.dat"}, {"test_data/transform_precoder_test_output_noise38.dat"}}, + {40, {"test_data/transform_precoder_test_input_data40.dat"}, {"test_data/transform_precoder_test_input_noise40.dat"}, {"test_data/transform_precoder_test_output_data40.dat"}, {"test_data/transform_precoder_test_output_noise40.dat"}}, + {45, {"test_data/transform_precoder_test_input_data42.dat"}, {"test_data/transform_precoder_test_input_noise42.dat"}, {"test_data/transform_precoder_test_output_data42.dat"}, {"test_data/transform_precoder_test_output_noise42.dat"}}, + {48, {"test_data/transform_precoder_test_input_data44.dat"}, {"test_data/transform_precoder_test_input_noise44.dat"}, {"test_data/transform_precoder_test_output_data44.dat"}, {"test_data/transform_precoder_test_output_noise44.dat"}}, + {50, {"test_data/transform_precoder_test_input_data46.dat"}, {"test_data/transform_precoder_test_input_noise46.dat"}, {"test_data/transform_precoder_test_output_data46.dat"}, {"test_data/transform_precoder_test_output_noise46.dat"}}, + {54, {"test_data/transform_precoder_test_input_data48.dat"}, {"test_data/transform_precoder_test_input_noise48.dat"}, {"test_data/transform_precoder_test_output_data48.dat"}, {"test_data/transform_precoder_test_output_noise48.dat"}}, + {60, {"test_data/transform_precoder_test_input_data50.dat"}, {"test_data/transform_precoder_test_input_noise50.dat"}, {"test_data/transform_precoder_test_output_data50.dat"}, {"test_data/transform_precoder_test_output_noise50.dat"}}, + {64, {"test_data/transform_precoder_test_input_data52.dat"}, {"test_data/transform_precoder_test_input_noise52.dat"}, {"test_data/transform_precoder_test_output_data52.dat"}, {"test_data/transform_precoder_test_output_noise52.dat"}}, + {72, {"test_data/transform_precoder_test_input_data54.dat"}, {"test_data/transform_precoder_test_input_noise54.dat"}, {"test_data/transform_precoder_test_output_data54.dat"}, {"test_data/transform_precoder_test_output_noise54.dat"}}, + {75, {"test_data/transform_precoder_test_input_data56.dat"}, {"test_data/transform_precoder_test_input_noise56.dat"}, {"test_data/transform_precoder_test_output_data56.dat"}, {"test_data/transform_precoder_test_output_noise56.dat"}}, + {80, {"test_data/transform_precoder_test_input_data58.dat"}, {"test_data/transform_precoder_test_input_noise58.dat"}, {"test_data/transform_precoder_test_output_data58.dat"}, {"test_data/transform_precoder_test_output_noise58.dat"}}, + {81, {"test_data/transform_precoder_test_input_data60.dat"}, {"test_data/transform_precoder_test_input_noise60.dat"}, {"test_data/transform_precoder_test_output_data60.dat"}, {"test_data/transform_precoder_test_output_noise60.dat"}}, + {90, {"test_data/transform_precoder_test_input_data62.dat"}, {"test_data/transform_precoder_test_input_noise62.dat"}, {"test_data/transform_precoder_test_output_data62.dat"}, {"test_data/transform_precoder_test_output_noise62.dat"}}, + {96, {"test_data/transform_precoder_test_input_data64.dat"}, {"test_data/transform_precoder_test_input_noise64.dat"}, {"test_data/transform_precoder_test_output_data64.dat"}, {"test_data/transform_precoder_test_output_noise64.dat"}}, + {100, {"test_data/transform_precoder_test_input_data66.dat"}, {"test_data/transform_precoder_test_input_noise66.dat"}, {"test_data/transform_precoder_test_output_data66.dat"}, {"test_data/transform_precoder_test_output_noise66.dat"}}, + {108, {"test_data/transform_precoder_test_input_data68.dat"}, {"test_data/transform_precoder_test_input_noise68.dat"}, {"test_data/transform_precoder_test_output_data68.dat"}, {"test_data/transform_precoder_test_output_noise68.dat"}}, + {120, {"test_data/transform_precoder_test_input_data70.dat"}, {"test_data/transform_precoder_test_input_noise70.dat"}, {"test_data/transform_precoder_test_output_data70.dat"}, {"test_data/transform_precoder_test_output_noise70.dat"}}, + {125, {"test_data/transform_precoder_test_input_data72.dat"}, {"test_data/transform_precoder_test_input_noise72.dat"}, {"test_data/transform_precoder_test_output_data72.dat"}, {"test_data/transform_precoder_test_output_noise72.dat"}}, + {128, {"test_data/transform_precoder_test_input_data74.dat"}, {"test_data/transform_precoder_test_input_noise74.dat"}, {"test_data/transform_precoder_test_output_data74.dat"}, {"test_data/transform_precoder_test_output_noise74.dat"}}, + {135, {"test_data/transform_precoder_test_input_data76.dat"}, {"test_data/transform_precoder_test_input_noise76.dat"}, {"test_data/transform_precoder_test_output_data76.dat"}, {"test_data/transform_precoder_test_output_noise76.dat"}}, + {144, {"test_data/transform_precoder_test_input_data78.dat"}, {"test_data/transform_precoder_test_input_noise78.dat"}, {"test_data/transform_precoder_test_output_data78.dat"}, {"test_data/transform_precoder_test_output_noise78.dat"}}, + {150, {"test_data/transform_precoder_test_input_data80.dat"}, {"test_data/transform_precoder_test_input_noise80.dat"}, {"test_data/transform_precoder_test_output_data80.dat"}, {"test_data/transform_precoder_test_output_noise80.dat"}}, + {160, {"test_data/transform_precoder_test_input_data82.dat"}, {"test_data/transform_precoder_test_input_noise82.dat"}, {"test_data/transform_precoder_test_output_data82.dat"}, {"test_data/transform_precoder_test_output_noise82.dat"}}, + {162, {"test_data/transform_precoder_test_input_data84.dat"}, {"test_data/transform_precoder_test_input_noise84.dat"}, {"test_data/transform_precoder_test_output_data84.dat"}, {"test_data/transform_precoder_test_output_noise84.dat"}}, + {180, {"test_data/transform_precoder_test_input_data86.dat"}, {"test_data/transform_precoder_test_input_noise86.dat"}, {"test_data/transform_precoder_test_output_data86.dat"}, {"test_data/transform_precoder_test_output_noise86.dat"}}, + {192, {"test_data/transform_precoder_test_input_data88.dat"}, {"test_data/transform_precoder_test_input_noise88.dat"}, {"test_data/transform_precoder_test_output_data88.dat"}, {"test_data/transform_precoder_test_output_noise88.dat"}}, + {200, {"test_data/transform_precoder_test_input_data90.dat"}, {"test_data/transform_precoder_test_input_noise90.dat"}, {"test_data/transform_precoder_test_output_data90.dat"}, {"test_data/transform_precoder_test_output_noise90.dat"}}, + {216, {"test_data/transform_precoder_test_input_data92.dat"}, {"test_data/transform_precoder_test_input_noise92.dat"}, {"test_data/transform_precoder_test_output_data92.dat"}, {"test_data/transform_precoder_test_output_noise92.dat"}}, + {225, {"test_data/transform_precoder_test_input_data94.dat"}, {"test_data/transform_precoder_test_input_noise94.dat"}, {"test_data/transform_precoder_test_output_data94.dat"}, {"test_data/transform_precoder_test_output_noise94.dat"}}, + {240, {"test_data/transform_precoder_test_input_data96.dat"}, {"test_data/transform_precoder_test_input_noise96.dat"}, {"test_data/transform_precoder_test_output_data96.dat"}, {"test_data/transform_precoder_test_output_noise96.dat"}}, + {243, {"test_data/transform_precoder_test_input_data98.dat"}, {"test_data/transform_precoder_test_input_noise98.dat"}, {"test_data/transform_precoder_test_output_data98.dat"}, {"test_data/transform_precoder_test_output_noise98.dat"}}, + {250, {"test_data/transform_precoder_test_input_data100.dat"}, {"test_data/transform_precoder_test_input_noise100.dat"}, {"test_data/transform_precoder_test_output_data100.dat"}, {"test_data/transform_precoder_test_output_noise100.dat"}}, + {256, {"test_data/transform_precoder_test_input_data102.dat"}, {"test_data/transform_precoder_test_input_noise102.dat"}, {"test_data/transform_precoder_test_output_data102.dat"}, {"test_data/transform_precoder_test_output_noise102.dat"}}, + {270, {"test_data/transform_precoder_test_input_data104.dat"}, {"test_data/transform_precoder_test_input_noise104.dat"}, {"test_data/transform_precoder_test_output_data104.dat"}, {"test_data/transform_precoder_test_output_noise104.dat"}}, // clang-format on }; diff --git a/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.tar.gz b/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.tar.gz index 91886a3368..1a4831c567 100644 --- a/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.tar.gz +++ b/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3bf66f2746922753afc2a12265adef9b4e715ea94fe4d7d715eb53e5facb3b7b -size 3658539 +oid sha256:ee487cb26fb7debf825b40c1fa00ecd2cc4d829c7966c439f7a7f7565d7e8c9c +size 5214972 diff --git a/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_vectortest.cpp b/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_vectortest.cpp index dedb93a69a..3aa6bed763 100644 --- a/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_vectortest.cpp +++ b/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_vectortest.cpp @@ -26,17 +26,31 @@ bool operator==(span lhs, span rhs) }); } -std::ostream& operator<<(std::ostream& os, span data) +bool operator==(span lhs, span rhs) +{ + return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](float left, float right) { + return std::abs(left - right) < 1e-5; + }); +} + +std::ostream& operator<<(std::ostream& os, span data) +{ + return os << fmt::format("{}", data); +} + +std::ostream& operator<<(std::ostream& os, span data) { return os << fmt::format("{}", data); } std::ostream& operator<<(std::ostream& os, const test_case_t& test_case) { - return os << fmt::format("{} {} {}", + return os << fmt::format("{} {} {} {} {}", test_case.M_rb, - test_case.deprecode_input.get_file_name(), - test_case.deprecode_output.get_file_name()); + test_case.deprecode_data_input.get_file_name(), + test_case.deprecode_noise_input.get_file_name(), + test_case.deprecode_data_output.get_file_name(), + test_case.deprecode_noise_output.get_file_name()); } } // namespace srsran @@ -79,20 +93,31 @@ TEST_P(TransformPrecodingFixture, FromVector) unsigned M_sc = M_rb * NRE; // Read precoder inputs and outputs. - std::vector deprecode_input = test_case.deprecode_input.read(); - std::vector deprecode_expected = test_case.deprecode_output.read(); - ASSERT_EQ(deprecode_input.size(), deprecode_expected.size()); - - std::vector deprecode_output(M_sc); - - unsigned nof_ofdm_symbols = deprecode_input.size() / M_sc; + const std::vector deprecode_data_input = test_case.deprecode_data_input.read(); + const std::vector deprecode_data_expected = test_case.deprecode_data_output.read(); + const std::vector deprecode_noise_input = test_case.deprecode_noise_input.read(); + const std::vector deprecode_noise_expected = test_case.deprecode_noise_output.read(); + ASSERT_EQ(deprecode_data_input.size(), deprecode_data_expected.size()); + ASSERT_EQ(deprecode_noise_input.size(), deprecode_noise_expected.size()); + ASSERT_EQ(deprecode_data_input.size(), deprecode_noise_input.size()); + + std::vector deprecode_data_output(M_sc); + std::vector deprecode_noise_output(M_sc); + + unsigned nof_ofdm_symbols = deprecode_data_input.size() / M_sc; for (unsigned i_ofdm_symbol = 0; i_ofdm_symbol != nof_ofdm_symbols; ++i_ofdm_symbol) { - span expected = span(deprecode_expected).subspan(i_ofdm_symbol * M_sc, M_sc); - span input = span(deprecode_input).subspan(i_ofdm_symbol * M_sc, M_sc); - span output = span(deprecode_output); - precoder->deprecode_ofdm_symbol(output, input); - - ASSERT_EQ(expected, span(output)); + span expected_data = span(deprecode_data_expected).subspan(i_ofdm_symbol * M_sc, M_sc); + span input_data = span(deprecode_data_input).subspan(i_ofdm_symbol * M_sc, M_sc); + span output_data = deprecode_data_output; + precoder->deprecode_ofdm_symbol(output_data, input_data); + + span expected_noise = span(deprecode_noise_expected).subspan(i_ofdm_symbol * M_sc, M_sc); + span input_noise = span(deprecode_noise_input).subspan(i_ofdm_symbol * M_sc, M_sc); + span output_noise = deprecode_noise_output; + precoder->deprecode_ofdm_symbol_noise(output_noise, input_noise); + + ASSERT_EQ(expected_data, span(output_data)); + ASSERT_EQ(expected_noise, span(output_noise)); } } diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.h b/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.h index 5cd5eefe3b..99cdc90825 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.h +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 19-07-2024 (seed 0): +// This file was generated using the following MATLAB class on 08-11-2024 (seed 0): // + "srsPUSCHDemodulatorUnittest.m" #include "../../../support/resource_grid_test_doubles.h" diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.tar.gz b/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.tar.gz index a29dc597af..e49525f73f 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.tar.gz +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f0fb3a846877ce8a202e5c6c2b1a448e9271ceeec618980a31cb94712f4487e2 -size 4113238 +oid sha256:939640d137f74e26c6ff529542a966360742e008ed33e870c40cc86dbd5cd672 +size 4113416 From b541f82cb81be5c557c658258a88930c12689322 Mon Sep 17 00:00:00 2001 From: yagoda Date: Mon, 11 Nov 2024 15:05:38 +0100 Subject: [PATCH 09/26] pdcp: disabling pdcp metrics if no E2 is present --- apps/units/cu_up/cu_up_builder.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/units/cu_up/cu_up_builder.cpp b/apps/units/cu_up/cu_up_builder.cpp index b07ad84b80..840d00d1c2 100644 --- a/apps/units/cu_up/cu_up_builder.cpp +++ b/apps/units/cu_up/cu_up_builder.cpp @@ -88,6 +88,9 @@ cu_up_unit srsran::build_cu_up(const cu_up_unit_config& unit_cfg, const cu_up_un for (auto& qos_ : config.qos) { qos_.second.pdcp_custom_cfg.metrics_notifier = pdcp_metric_notifier; + if (!pdcp_metric_notifier) { // Disable PDCP metrics if E2 is not enabled since there is no consumer. + qos_.second.pdcp_custom_cfg.metrics_period = std::chrono::milliseconds(0); + } } wrapper.unit = From 4a4ea2c77ba34e03d0ea8f72df7bb3910fcaf257 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 11 Nov 2024 14:35:39 +0100 Subject: [PATCH 10/26] rlc_rx_am: adjust memory order of atomic exchange of status PDU --- lib/rlc/rlc_rx_am_entity.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/rlc/rlc_rx_am_entity.cpp b/lib/rlc/rlc_rx_am_entity.cpp index 31554e3fe6..bfd2669863 100644 --- a/lib/rlc/rlc_rx_am_entity.cpp +++ b/lib/rlc/rlc_rx_am_entity.cpp @@ -632,7 +632,7 @@ void rlc_rx_am_entity::store_status_report() { // Minor inacurracy between status_report_size and status_for_exchange is tolerated here uint32_t latest_status_report_size = status_owned_by_writer->get_packed_size(); - status_owned_by_writer = status_for_exchange.exchange(status_owned_by_writer, std::memory_order_relaxed); + status_owned_by_writer = status_for_exchange.exchange(status_owned_by_writer, std::memory_order_release); status_report_size.store(latest_status_report_size, std::memory_order_release); } @@ -645,7 +645,7 @@ rlc_am_status_pdu& rlc_rx_am_entity::get_status_pdu() } status_prohibit_timer_is_running.store(true, std::memory_order_relaxed); } - status_owned_by_reader = status_for_exchange.exchange(status_owned_by_reader, std::memory_order_relaxed); + status_owned_by_reader = status_for_exchange.exchange(status_owned_by_reader, std::memory_order_acquire); return *status_owned_by_reader; } From 7c55d5197fd26fdf2ceadbac9725feb0ed76e6b5 Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Thu, 7 Nov 2024 12:33:35 +0100 Subject: [PATCH 11/26] phy: initial dmrs estimator pucch formats 3 and 4 --- .../phy/upper/pucch_formats_3_4_helpers.h | 2 + .../signal_processor_factories.h | 8 +- .../upper/signal_processors/CMakeLists.txt | 1 + .../dmrs_pucch_processor_format1_impl.cpp | 14 +- .../pucch/dmrs_pucch_processor_format1_impl.h | 2 +- .../dmrs_pucch_processor_format2_impl.cpp | 20 +-- .../pucch/dmrs_pucch_processor_format2_impl.h | 1 - .../dmrs_pucch_processor_formats_3_4_impl.cpp | 136 ++++++++++++++++++ .../dmrs_pucch_processor_formats_3_4_impl.h | 75 ++++++++++ .../signal_processor_factories.cpp | 18 ++- lib/phy/upper/upper_phy_factories.cpp | 2 +- .../pucch/pucch_processor_benchmark.cpp | 2 +- .../pucch_processor_format0_vectortest.cpp | 2 +- .../pucch_processor_format1_vectortest.cpp | 2 +- .../pucch_processor_format2_vectortest.cpp | 2 +- ...pucch_processor_validator_format0_test.cpp | 2 +- ...pucch_processor_validator_format1_test.cpp | 2 +- ...pucch_processor_validator_format2_test.cpp | 2 +- .../dmrs_pucch_processor_test.cpp | 7 +- .../dmrs_pucch_processor_test_data.h | 34 +++-- .../dmrs_pucch_processor_test_data.tar.gz | 4 +- .../dmrs_pucch_processor_test_doubles.h | 9 ++ 22 files changed, 303 insertions(+), 44 deletions(-) create mode 100644 lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.cpp create mode 100644 lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.h diff --git a/include/srsran/phy/upper/pucch_formats_3_4_helpers.h b/include/srsran/phy/upper/pucch_formats_3_4_helpers.h index f6360be26f..4ae41206e2 100644 --- a/include/srsran/phy/upper/pucch_formats_3_4_helpers.h +++ b/include/srsran/phy/upper/pucch_formats_3_4_helpers.h @@ -14,7 +14,9 @@ #pragma once #include "srsran/adt/bounded_integer.h" +#include "srsran/phy/generic_functions/transform_precoding/transform_precoder.h" #include "srsran/phy/support/mask_types.h" +#include "srsran/phy/support/resource_grid_reader.h" #include "srsran/phy/upper/equalization/modular_ch_est_list.h" #include "srsran/ran/pucch/pucch_constants.h" diff --git a/include/srsran/phy/upper/signal_processors/signal_processor_factories.h b/include/srsran/phy/upper/signal_processors/signal_processor_factories.h index 9309b9e089..0b4754dee2 100644 --- a/include/srsran/phy/upper/signal_processors/signal_processor_factories.h +++ b/include/srsran/phy/upper/signal_processors/signal_processor_factories.h @@ -54,14 +54,16 @@ create_dmrs_pdsch_processor_factory_sw(std::shared_ptr create_format1() = 0; - virtual std::unique_ptr create_format2() = 0; + virtual ~dmrs_pucch_estimator_factory() = default; + virtual std::unique_ptr create_format1() = 0; + virtual std::unique_ptr create_format2() = 0; + virtual std::unique_ptr create_formats3_4() = 0; }; std::shared_ptr create_dmrs_pucch_estimator_factory_sw(std::shared_ptr prg_factory, std::shared_ptr lpc_factory, + std::shared_ptr lpg_factory, std::shared_ptr ch_estimator_factory); class dmrs_pusch_estimator_factory diff --git a/lib/phy/upper/signal_processors/CMakeLists.txt b/lib/phy/upper/signal_processors/CMakeLists.txt index 464ddb3ee5..221e77371d 100644 --- a/lib/phy/upper/signal_processors/CMakeLists.txt +++ b/lib/phy/upper/signal_processors/CMakeLists.txt @@ -11,6 +11,7 @@ set(SOURCES ptrs/ptrs_pdsch_generator_factory.cpp pucch/dmrs_pucch_processor_format1_impl.cpp pucch/dmrs_pucch_processor_format2_impl.cpp + pucch/dmrs_pucch_processor_formats_3_4_impl.cpp srs/srs_estimator_factory.cpp srs/srs_estimator_generic_impl.cpp srs/srs_validator_generic_impl.cpp diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp index 82c5b5e203..8957f66770 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp @@ -123,10 +123,10 @@ dmrs_pucch_processor_format1_impl::generate_dmrs_pattern(const config_t& config) return mask; } -void dmrs_pucch_processor_format1_impl::generate_sequence(span sequence, - const dmrs_pucch_processor::config_t& pucch_config, - const sequence_generation_config& cfg, - unsigned symbol) const +void dmrs_pucch_processor_format1_impl::generate_sequence(span sequence, + const config_t& pucch_config, + const sequence_generation_config& cfg, + unsigned symbol) const { // Compute alpha index. unsigned alpha_idx = helper.get_alpha_index( @@ -143,9 +143,9 @@ void dmrs_pucch_processor_format1_impl::generate_sequence(span srsvec::sc_prod(r_uv, w_i_m, sequence); } -void dmrs_pucch_processor_format1_impl::estimate(channel_estimate& estimate, - const resource_grid_reader& grid, - const dmrs_pucch_processor::config_t& config) +void dmrs_pucch_processor_format1_impl::estimate(channel_estimate& estimate, + const resource_grid_reader& grid, + const config_t& config) { srsran_assert(config.nof_prb <= 1, "PUCCH Format 1 occupies a single PRB."); diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h index dd1fe35d31..9be25a761c 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h @@ -64,7 +64,7 @@ class dmrs_pucch_processor_format1_impl : public dmrs_pucch_processor /// \param[in] pucch_config PUCCH configuration. /// \param[in] gen_config Additional parameters required to calculate the sequences. /// \param[in] symbol OFDM symbol index. - void generate_sequence(span sequence, + void generate_sequence(span sequence, const config_t& pucch_config, const sequence_generation_config& gen_config, unsigned symbol) const; diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format2_impl.cpp b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format2_impl.cpp index 6402bbeabf..51b876a730 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format2_impl.cpp +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format2_impl.cpp @@ -9,7 +9,7 @@ */ #include "dmrs_pucch_processor_format2_impl.h" -#include "srsran/srsvec/prod.h" +#include "srsran/ran/pucch/pucch_constants.h" using namespace srsran; @@ -19,7 +19,7 @@ using namespace srsran; static const bounded_bitset format2_prb_re_mask = {false, true, false, false, true, false, false, true, false, false, true, false}; -unsigned dmrs_pucch_processor_format2_impl::c_init(unsigned symbol, const dmrs_pucch_processor::config_t& config) +unsigned dmrs_pucch_processor_format2_impl::c_init(unsigned symbol, const config_t& config) { uint64_t n_slot = config.slot.slot_index(); uint64_t n_id = config.n_id_0; @@ -27,10 +27,10 @@ unsigned dmrs_pucch_processor_format2_impl::c_init(unsigned symbol, const dmrs_p return ((get_nsymb_per_slot(config.cp) * n_slot + symbol + 1) * (2 * n_id + 1) * pow2(17) + 2 * n_id) % pow2(31); } -void dmrs_pucch_processor_format2_impl::generate_sequence(span sequence, - unsigned symbol, - unsigned starting_prb, - const dmrs_pucch_processor::config_t& config) +void dmrs_pucch_processor_format2_impl::generate_sequence(span sequence, + unsigned symbol, + unsigned starting_prb, + const config_t& config) { // Initialize pseudo-random generator. prg->init(c_init(symbol, config)); @@ -59,7 +59,7 @@ dmrs_pucch_processor_format2_impl::generate_dmrs_pattern(const config_t& config) mask.rb_mask2.resize(config.second_hop_prb + config.nof_prb); mask.rb_mask2.fill(config.second_hop_prb, config.second_hop_prb + config.nof_prb, true); - // Set the hopping symbol index, indicating the start of the second hop. Recall that PUCCH Format 1 occupies a + // Set the hopping symbol index, indicating the start of the second hop. Recall that PUCCH Format 2 occupies a // maximum of 2 OFDM symbols. mask.hopping_symbol_index = config.start_symbol_index + 1; } @@ -71,9 +71,9 @@ dmrs_pucch_processor_format2_impl::generate_dmrs_pattern(const config_t& config) return mask; } -void dmrs_pucch_processor_format2_impl::estimate(channel_estimate& estimate, - const resource_grid_reader& grid, - const dmrs_pucch_processor::config_t& config) +void dmrs_pucch_processor_format2_impl::estimate(channel_estimate& estimate, + const resource_grid_reader& grid, + const config_t& config) { srsran_assert((!config.intra_slot_hopping || (config.nof_symbols > pucch_constants::FORMAT2_MIN_NSYMB)), "Frequency hopping requires {} OFDM symbols.", diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format2_impl.h b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format2_impl.h index fcf29f3750..3eef347090 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format2_impl.h +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format2_impl.h @@ -13,7 +13,6 @@ #include "srsran/phy/upper/sequence_generators/pseudo_random_generator.h" #include "srsran/phy/upper/signal_processors/dmrs_pucch_processor.h" #include "srsran/phy/upper/signal_processors/port_channel_estimator.h" -#include "srsran/ran/pucch/pucch_constants.h" namespace srsran { diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.cpp b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.cpp new file mode 100644 index 0000000000..bc58fe2701 --- /dev/null +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.cpp @@ -0,0 +1,136 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "dmrs_pucch_processor_formats_3_4_impl.h" +#include "srsran/phy/upper/pucch_formats_3_4_helpers.h" +#include "srsran/ran/pucch/pucch_constants.h" + +using namespace srsran; + +void dmrs_pucch_processor_formats_3_4_impl::generate_sequence(span sequence, + const config_t& config, + const sequence_generation_config& gen_config, + unsigned symbol) +{ + unsigned m_0 = 0; + // m_0 for PUCCH Format 4 is selected according to TS38.211 Table 6.4.1.3.3.1-1. + if (config.format == pucch_format::FORMAT_4) { + switch (config.time_domain_occ) { + case 0: + m_0 = 0; + break; + case 1: + m_0 = 6; + break; + case 2: + m_0 = 3; + break; + case 3: + m_0 = 9; + break; + default: + break; + } + } + + // Compute alpha index. + unsigned alpha_idx = helper.get_alpha_index(config.slot, config.cp, config.n_id, symbol, m_0, 0); + + // Generate the r_uv sequence. + low_papr_generator->generate(sequence, gen_config.u, gen_config.v, alpha_idx, NRE); +} + +dmrs_pucch_processor_formats_3_4_impl::layer_dmrs_pattern +dmrs_pucch_processor_formats_3_4_impl::generate_dmrs_pattern(const config_t& config) +{ + layer_dmrs_pattern mask; + + // All RE within the PRB are allocated to DM-RS. + mask.re_pattern = ~bounded_bitset(NRE); + + // Set PRB allocation. + mask.rb_mask.resize(config.starting_prb + config.nof_prb); + mask.rb_mask.fill(config.starting_prb, config.starting_prb + config.nof_prb, true); + + if (config.intra_slot_hopping) { + // Set second hop PRB allocation. + mask.rb_mask2.resize(config.second_hop_prb + config.nof_prb); + mask.rb_mask2.fill(config.second_hop_prb, config.second_hop_prb + config.nof_prb, true); + + // Set the hopping symbol index, indicating the start of the second hop. In case of a PUCCH allocation with an odd + // number of symbols, the second hop is one symbol larger than the first one. + mask.hopping_symbol_index = config.start_symbol_index + (config.nof_symbols / 2); + } + + symbol_slot_mask dmrs_symb_mask = + get_pucch_formats_3_4_dmrs_symbol_mask(config.nof_symbols, config.intra_slot_hopping, config.additional_dmrs); + + mask.symbols.resize(get_nsymb_per_slot(config.cp)); + dmrs_symb_mask.for_each(0, config.nof_symbols, [&mask, &config](unsigned bitpos) { + mask.symbols.set(config.start_symbol_index + bitpos); + }); + + return mask; +} + +void dmrs_pucch_processor_formats_3_4_impl::estimate(channel_estimate& estimate, + const resource_grid_reader& grid, + const config_t& config) +{ + srsran_assert(!((config.format == pucch_format::FORMAT_4) && (config.nof_prb > 1)), + "PUCCH Format 4 occupies a single PRB"); + + unsigned nof_rx_ports = config.ports.size(); + + symbol_slot_mask dmrs_symb_mask = + get_pucch_formats_3_4_dmrs_symbol_mask(config.nof_symbols, config.intra_slot_hopping, config.additional_dmrs); + + // Prepare DM-RS symbol buffer dimensions. + re_measurement_dimensions dims; + dims.nof_subc = config.nof_prb * NRE; + dims.nof_symbols = dmrs_symb_mask.count(); + dims.nof_slices = pucch_constants::MAX_LAYERS; + + // Resize DM-RS symbol buffer. + temp_symbols.resize(dims); + + unsigned u, v; + helper.compute_group_sequence(config.group_hopping, config.n_id, u, v); + + unsigned i_symb_start = config.start_symbol_index; + unsigned i_symb_end = config.start_symbol_index + config.nof_symbols; + + unsigned i_dmrs_symb = 0; + for (unsigned i_symb = i_symb_start; i_symb != i_symb_end; ++i_symb) { + // For each symbol carrying DM-RS. + if (!dmrs_symb_mask.test(i_symb - config.start_symbol_index)) { + continue; + } + + sequence_generation_config cfg = {.u = u, .v = v}; + generate_sequence(temp_symbols.get_symbol(i_dmrs_symb, 0), config, cfg, i_symb); + ++i_dmrs_symb; + } + + // Prepare channel estimator configuration. + port_channel_estimator::configuration est_cfg; + est_cfg.scs = to_subcarrier_spacing(config.slot.numerology()); + est_cfg.cp = config.cp; + est_cfg.first_symbol = config.start_symbol_index; + est_cfg.nof_symbols = config.nof_symbols; + est_cfg.dmrs_pattern = {generate_dmrs_pattern(config)}; + est_cfg.rx_ports = config.ports; + est_cfg.scaling = 1.0F; + + // Perform estimation for each receive port. + for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { + ch_estimator->compute(estimate, grid, i_port, temp_symbols, est_cfg); + } +} \ No newline at end of file diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.h b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.h new file mode 100644 index 0000000000..1233b015f8 --- /dev/null +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.h @@ -0,0 +1,75 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "srsran/phy/upper/pucch_helper.h" +#include "srsran/phy/upper/sequence_generators/low_papr_sequence_generator.h" +#include "srsran/phy/upper/sequence_generators/pseudo_random_generator.h" +#include "srsran/phy/upper/signal_processors/dmrs_pucch_processor.h" +#include "srsran/phy/upper/signal_processors/port_channel_estimator.h" + +namespace srsran { + +/// Generic implementation of a DM-RS channel estimator for PUCCH Formats 3 and 4. +class dmrs_pucch_processor_formats_3_4_impl : public dmrs_pucch_processor +{ +public: + using layer_dmrs_pattern = port_channel_estimator::layer_dmrs_pattern; + + dmrs_pucch_processor_formats_3_4_impl(std::unique_ptr prg_, + std::unique_ptr low_papr_generator_, + std::unique_ptr ch_est_) : + helper(std::move(prg_)), low_papr_generator(std::move(low_papr_generator_)), ch_estimator(std::move(ch_est_)) + { + srsran_assert(low_papr_generator, "Invalid sequence generator."); + srsran_assert(ch_estimator, "Invalid port channel estimator."); + } + + void estimate(channel_estimate& ce_, const resource_grid_reader& grid, const config_t& config) override; + +private: + pucch_helper helper; + + /// PUCCH Formats 3 and 4 implementation expects pre-generated sequence collection on instantiation. + std::unique_ptr low_papr_generator; + /// Antenna port channel estimator. + std::unique_ptr ch_estimator; + + /// Buffer for DM-RS symbols. + dmrs_symbol_list temp_symbols; + + /// Holds DM-RS sequence generation parameters used in TS38.211 Section 6.4.1.3.3.1. + struct sequence_generation_config { + // Sequence group. + unsigned u; + // Sequence number. + unsigned v; + }; + + /// \brief Generates a DM-RS sequence according to TS38.211 Section 6.4.1.3.2.1. + /// + /// \param[out] sequence Sequence destination. + /// \param[in] symbol Symbol index. + /// \param[in] gen_config Additional parameters required to calculate the sequences. + /// \param[in] config Required parameters to calculate the sequences. + void generate_sequence(span sequence, + const config_t& config, + const sequence_generation_config& gen_config, + unsigned symbol); + + /// \brief Generates the PUCCH DM-RS allocation pattern. + /// + /// Implements the PUCCH DM-RS mapping, as described in TS38.211 Section 6.4.1.3.3.2. + /// \param[in] config Configuration parameters. + /// \return The DM-RS allocation pattern. + static layer_dmrs_pattern generate_dmrs_pattern(const config_t& config); +}; +} // namespace srsran diff --git a/lib/phy/upper/signal_processors/signal_processor_factories.cpp b/lib/phy/upper/signal_processors/signal_processor_factories.cpp index 45449226fc..7addaad2e2 100644 --- a/lib/phy/upper/signal_processors/signal_processor_factories.cpp +++ b/lib/phy/upper/signal_processors/signal_processor_factories.cpp @@ -19,11 +19,14 @@ #include "pss_processor_impl.h" #include "pucch/dmrs_pucch_processor_format1_impl.h" #include "pucch/dmrs_pucch_processor_format2_impl.h" +#include "pucch/dmrs_pucch_processor_formats_3_4_impl.h" #include "sss_processor_impl.h" + #include "srsran/phy/support/support_factories.h" #include "srsran/phy/support/support_formatters.h" #include "srsran/phy/support/time_alignment_estimator/time_alignment_estimator_factories.h" #include "srsran/phy/upper/signal_processors/signal_processor_formatters.h" +#include "srsran/ran/pucch/pucch_constants.h" using namespace srsran; @@ -93,13 +96,16 @@ class dmrs_pucch_estimator_sw_factory : public dmrs_pucch_estimator_factory public: dmrs_pucch_estimator_sw_factory(std::shared_ptr& prg_factory_, std::shared_ptr& lpc_factory_, + std::shared_ptr& lpg_factory_, std::shared_ptr& ch_estimator_factory_) : prg_factory(std::move(prg_factory_)), lpc_factory(std::move(lpc_factory_)), + lpg_factory(std::move(lpg_factory_)), ch_estimator_factory(std::move(ch_estimator_factory_)) { srsran_assert(prg_factory, "Invalid sequence generator factory."); srsran_assert(lpc_factory, "Invalid sequence collection factory."); + srsran_assert(lpg_factory, "Invalid sequence generator factory."); srsran_assert(ch_estimator_factory, "Invalid channel estimator factory."); } @@ -125,9 +131,18 @@ class dmrs_pucch_estimator_sw_factory : public dmrs_pucch_estimator_factory prg_factory->create(), ch_estimator_factory->create(port_channel_estimator_fd_smoothing_strategy::filter)); } + std::unique_ptr create_formats3_4() override + { + return std::make_unique( + prg_factory->create(), + lpg_factory->create(), + ch_estimator_factory->create(port_channel_estimator_fd_smoothing_strategy::mean, /*compensate_cfo =*/false)); + } + private: std::shared_ptr prg_factory; std::shared_ptr lpc_factory; + std::shared_ptr lpg_factory; std::shared_ptr ch_estimator_factory; }; @@ -295,9 +310,10 @@ srsran::create_dmrs_pdsch_processor_factory_sw(std::shared_ptr srsran::create_dmrs_pucch_estimator_factory_sw(std::shared_ptr prg_factory, std::shared_ptr lpc_factory, + std::shared_ptr lpg_factory, std::shared_ptr ch_estimator_factory) { - return std::make_shared(prg_factory, lpc_factory, ch_estimator_factory); + return std::make_shared(prg_factory, lpc_factory, lpg_factory, ch_estimator_factory); } std::shared_ptr srsran::create_dmrs_pusch_estimator_factory_sw( diff --git a/lib/phy/upper/upper_phy_factories.cpp b/lib/phy/upper/upper_phy_factories.cpp index 5992f0e088..5635121166 100644 --- a/lib/phy/upper/upper_phy_factories.cpp +++ b/lib/phy/upper/upper_phy_factories.cpp @@ -519,7 +519,7 @@ static std::shared_ptr create_ul_processor_factory(con report_fatal_error_if_not(port_chan_estimator_factory, "Invalid port channel estimator factory."); std::shared_ptr pucch_dmrs_factory = - create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, port_chan_estimator_factory); + create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, lpg_factory, port_chan_estimator_factory); report_fatal_error_if_not(pucch_dmrs_factory, "Invalid PUCCH DM-RS estimator factory."); std::shared_ptr pseudorandom = create_pseudo_random_generator_sw_factory(); diff --git a/tests/benchmarks/phy/upper/channel_processors/pucch/pucch_processor_benchmark.cpp b/tests/benchmarks/phy/upper/channel_processors/pucch/pucch_processor_benchmark.cpp index 150f60204f..0df025ff0f 100644 --- a/tests/benchmarks/phy/upper/channel_processors/pucch/pucch_processor_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_processors/pucch/pucch_processor_benchmark.cpp @@ -334,7 +334,7 @@ static pucch_processor_factory& get_pucch_processor_factory() TESTASSERT(port_chan_estimator_factory); std::shared_ptr estimator_factory = - create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, port_chan_estimator_factory); + create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, lpg_factory, port_chan_estimator_factory); TESTASSERT(estimator_factory); // Create PUCCH detector factory. diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format0_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format0_vectortest.cpp index d01abc9b23..51e0b26c02 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format0_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format0_vectortest.cpp @@ -90,7 +90,7 @@ class PucchProcessorFormat0Fixture : public ::testing::TestWithParam estimator_factory = - create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, port_chan_estimator_factory); + create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, lpg_factory, port_chan_estimator_factory); ASSERT_NE(estimator_factory, nullptr) << "Cannot create DM-RS PUCCH estimator factory."; // Create factories required by the PUCCH demodulator factory. diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format1_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format1_vectortest.cpp index 0bfc8ff804..c06862597e 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format1_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format1_vectortest.cpp @@ -92,7 +92,7 @@ class PucchProcessorFormat1Fixture : public ::testing::TestWithParam estimator_factory = - create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, port_chan_estimator_factory); + create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, lpg_factory, port_chan_estimator_factory); ASSERT_NE(estimator_factory, nullptr) << "Cannot create DM-RS PUCCH estimator factory."; // Create factories required by the PUCCH demodulator factory. diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format2_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format2_vectortest.cpp index fce1296838..65e945922d 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format2_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format2_vectortest.cpp @@ -93,7 +93,7 @@ class PucchProcessorF2Fixture : public ::testing::TestWithParam estimator_factory = - create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, port_chan_estimator_factory); + create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, lpg_factory, port_chan_estimator_factory); ASSERT_NE(estimator_factory, nullptr) << "Cannot create DM-RS PUCCH estimator factory."; // Create PUCCH detector factory. diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_validator_format0_test.cpp b/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_validator_format0_test.cpp index 9a7d09591d..5aa567eda6 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_validator_format0_test.cpp +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_validator_format0_test.cpp @@ -242,7 +242,7 @@ class PucchProcessorFormat0Fixture : public ::testing::TestWithParam estimator_factory = - create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, port_chan_estimator_factory); + create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, lpg_factory, port_chan_estimator_factory); ASSERT_NE(estimator_factory, nullptr) << "Cannot create DM-RS PUCCH estimator factory."; // Create PUCCH detector factory. diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_validator_format1_test.cpp b/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_validator_format1_test.cpp index 5f5cbade2f..e7f0c5244c 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_validator_format1_test.cpp +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_validator_format1_test.cpp @@ -225,7 +225,7 @@ class PucchProcessorFormat1Fixture : public ::testing::TestWithParam estimator_factory = - create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, port_chan_estimator_factory); + create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, lpg_factory, port_chan_estimator_factory); ASSERT_NE(estimator_factory, nullptr) << "Cannot create DM-RS PUCCH estimator factory."; // Create PUCCH detector factory. diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_validator_format2_test.cpp b/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_validator_format2_test.cpp index 7b59bc4a67..9510187d2c 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_validator_format2_test.cpp +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_validator_format2_test.cpp @@ -272,7 +272,7 @@ class PucchProcessorFormat2Fixture : public ::testing::TestWithParam estimator_factory = - create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, port_chan_estimator_factory); + create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, lpg_factory, port_chan_estimator_factory); ASSERT_NE(estimator_factory, nullptr) << "Cannot create DM-RS PUCCH estimator factory."; // Create PUCCH detector factory. diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test.cpp b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test.cpp index f58aed6e38..5e750493c1 100644 --- a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test.cpp +++ b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test.cpp @@ -73,7 +73,8 @@ class DmrsPucchProcessorFixture : public ::testing::TestWithParam ASSERT_NE(port_chan_estimator_factory, nullptr) << "Cannot create port channel estimator factory."; // Create DM-RS for PUCCH estimator factory. - estimator_factory = create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, port_chan_estimator_factory); + estimator_factory = + create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, lpg_factory, port_chan_estimator_factory); ASSERT_NE(estimator_factory, nullptr) << "Cannot create PUCCH estimator factory."; } } @@ -91,9 +92,11 @@ class DmrsPucchProcessorFixture : public ::testing::TestWithParam break; case pucch_format::FORMAT_2: dmrs_pucch = estimator_factory->create_format2(); - case pucch_format::FORMAT_0: + break; case pucch_format::FORMAT_3: case pucch_format::FORMAT_4: + dmrs_pucch = estimator_factory->create_formats3_4(); + case pucch_format::FORMAT_0: case pucch_format::NOF_FORMATS: default: break; diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.h b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.h index 68d3ec0c81..3c770a2fc3 100644 --- a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.h +++ b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 13-12-2023 (seed 0): +// This file was generated using the following MATLAB class on 07-11-2024 (seed 0): // + "srsPUCCHdmrsUnittest.m" #include "../../support/resource_grid_test_doubles.h" @@ -34,14 +34,30 @@ static const std::vector dmrs_pucch_processor_test_data = { {{pucch_format::FORMAT_2, {0, 4}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 1, 2, 51, false, 0, 1, 9, 0, false, 771, 771, {1}}, {"test_data/dmrs_pucch_processor_test_output5.dat"}}, {{pucch_format::FORMAT_2, {0, 8}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 9, 2, 48, true, 27, 1, 0, 0, false, 98, 98, {7}}, {"test_data/dmrs_pucch_processor_test_output6.dat"}}, {{pucch_format::FORMAT_2, {0, 8}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 2, 7, true, 12, 4, 7, 0, false, 745, 745, {7}}, {"test_data/dmrs_pucch_processor_test_output7.dat"}}, - {{pucch_format::FORMAT_1, {1, 12}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 14, 21, false, 0, 1, 4, 6, false, 173, 173, {7}}, {"test_data/dmrs_pucch_processor_test_output8.dat"}}, - {{pucch_format::FORMAT_1, {1, 13}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 11, 17, false, 0, 1, 9, 1, false, 332, 332, {7}}, {"test_data/dmrs_pucch_processor_test_output9.dat"}}, - {{pucch_format::FORMAT_1, {1, 13}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 1, 12, 31, true, 29, 1, 4, 1, false, 634, 634, {4}}, {"test_data/dmrs_pucch_processor_test_output10.dat"}}, - {{pucch_format::FORMAT_1, {1, 10}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 6, 7, 51, true, 17, 1, 8, 0, false, 555, 555, {0}}, {"test_data/dmrs_pucch_processor_test_output11.dat"}}, - {{pucch_format::FORMAT_2, {1, 17}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 9, 1, 11, false, 0, 3, 4, 0, false, 970, 970, {3}}, {"test_data/dmrs_pucch_processor_test_output12.dat"}}, - {{pucch_format::FORMAT_2, {1, 15}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 2, 43, false, 0, 9, 0, 0, false, 395, 395, {5}}, {"test_data/dmrs_pucch_processor_test_output13.dat"}}, - {{pucch_format::FORMAT_2, {1, 7}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 5, 2, 11, true, 33, 5, 8, 0, false, 931, 931, {5}}, {"test_data/dmrs_pucch_processor_test_output14.dat"}}, - {{pucch_format::FORMAT_2, {1, 4}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 2, 2, 39, true, 2, 13, 9, 0, false, 698, 698, {1}}, {"test_data/dmrs_pucch_processor_test_output15.dat"}}, + {{pucch_format::FORMAT_3, {0, 6}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 14, 21, false, 0, 16, 4, 0, true, 173, 173, {7}}, {"test_data/dmrs_pucch_processor_test_output8.dat"}}, + {{pucch_format::FORMAT_3, {0, 7}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 1, 11, 12, false, 0, 4, 7, 0, true, 332, 332, {2}}, {"test_data/dmrs_pucch_processor_test_output9.dat"}}, + {{pucch_format::FORMAT_3, {0, 7}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 7, 4, 30, true, 43, 8, 6, 0, false, 634, 634, {4}}, {"test_data/dmrs_pucch_processor_test_output10.dat"}}, + {{pucch_format::FORMAT_3, {0, 3}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 2, 5, 21, true, 35, 3, 5, 0, true, 555, 555, {7}}, {"test_data/dmrs_pucch_processor_test_output11.dat"}}, + {{pucch_format::FORMAT_4, {0, 0}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 3, 4, 40, false, 0, 1, 11, 0, true, 970, 970, {6}}, {"test_data/dmrs_pucch_processor_test_output12.dat"}}, + {{pucch_format::FORMAT_4, {0, 4}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 13, 9, false, 0, 1, 2, 0, false, 395, 395, {4}}, {"test_data/dmrs_pucch_processor_test_output13.dat"}}, + {{pucch_format::FORMAT_4, {0, 4}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 5, 4, 5, true, 27, 1, 10, 0, false, 931, 931, {1}}, {"test_data/dmrs_pucch_processor_test_output14.dat"}}, + {{pucch_format::FORMAT_4, {0, 9}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 5, 4, 20, true, 7, 1, 1, 1, true, 698, 698, {5}}, {"test_data/dmrs_pucch_processor_test_output15.dat"}}, + {{pucch_format::FORMAT_1, {1, 7}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 1, 10, 37, false, 0, 1, 11, 4, false, 293, 293, {7}}, {"test_data/dmrs_pucch_processor_test_output16.dat"}}, + {{pucch_format::FORMAT_1, {1, 2}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 4, 8, 43, false, 0, 1, 7, 3, false, 243, 243, {5}}, {"test_data/dmrs_pucch_processor_test_output17.dat"}}, + {{pucch_format::FORMAT_1, {1, 6}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 4, 7, 28, true, 18, 1, 11, 0, false, 280, 280, {4}}, {"test_data/dmrs_pucch_processor_test_output18.dat"}}, + {{pucch_format::FORMAT_1, {1, 15}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 14, 36, true, 43, 1, 5, 0, false, 691, 691, {3}}, {"test_data/dmrs_pucch_processor_test_output19.dat"}}, + {{pucch_format::FORMAT_2, {1, 14}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 2, 1, 18, false, 0, 11, 0, 0, false, 31, 31, {7}}, {"test_data/dmrs_pucch_processor_test_output20.dat"}}, + {{pucch_format::FORMAT_2, {1, 14}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 5, 1, 34, false, 0, 1, 7, 0, false, 642, 642, {4}}, {"test_data/dmrs_pucch_processor_test_output21.dat"}}, + {{pucch_format::FORMAT_2, {1, 4}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 10, 2, 14, true, 26, 12, 10, 0, false, 360, 360, {5}}, {"test_data/dmrs_pucch_processor_test_output22.dat"}}, + {{pucch_format::FORMAT_2, {1, 11}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 4, 2, 26, true, 12, 8, 9, 0, false, 407, 407, {2}}, {"test_data/dmrs_pucch_processor_test_output23.dat"}}, + {{pucch_format::FORMAT_3, {1, 19}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 2, 10, 9, false, 0, 10, 11, 0, true, 39, 39, {0}}, {"test_data/dmrs_pucch_processor_test_output24.dat"}}, + {{pucch_format::FORMAT_3, {1, 16}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 3, 6, 50, false, 0, 2, 1, 0, true, 21, 21, {0}}, {"test_data/dmrs_pucch_processor_test_output25.dat"}}, + {{pucch_format::FORMAT_3, {1, 5}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 13, 18, true, 22, 2, 1, 0, true, 459, 459, {2}}, {"test_data/dmrs_pucch_processor_test_output26.dat"}}, + {{pucch_format::FORMAT_3, {1, 0}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 2, 11, 41, true, 1, 8, 8, 0, true, 959, 959, {2}}, {"test_data/dmrs_pucch_processor_test_output27.dat"}}, + {{pucch_format::FORMAT_4, {1, 3}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 10, 45, false, 0, 1, 8, 1, true, 859, 859, {5}}, {"test_data/dmrs_pucch_processor_test_output28.dat"}}, + {{pucch_format::FORMAT_4, {1, 14}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 1, 10, 24, false, 0, 1, 5, 2, false, 260, 260, {6}}, {"test_data/dmrs_pucch_processor_test_output29.dat"}}, + {{pucch_format::FORMAT_4, {1, 9}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 11, 40, true, 14, 1, 9, 0, true, 302, 302, {2}}, {"test_data/dmrs_pucch_processor_test_output30.dat"}}, + {{pucch_format::FORMAT_4, {1, 16}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 14, 45, true, 32, 1, 7, 1, true, 652, 652, {7}}, {"test_data/dmrs_pucch_processor_test_output31.dat"}}, // clang-format on }; diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.tar.gz b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.tar.gz index 8f6a22bdef..93d81e8542 100644 --- a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.tar.gz +++ b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:850b9c0896bde3f41fb11440bdcce144872155eed7c7667a3ea5a151f29be069 -size 3387 +oid sha256:4ee50257ffd22058fbf14963f3a7b58348c911fb17a4684bf443d3df554634a2 +size 17774 diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_doubles.h b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_doubles.h index 6ecc9e15a4..608450802d 100644 --- a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_doubles.h +++ b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_doubles.h @@ -59,12 +59,21 @@ class dmrs_pucch_estimator_factory_spy : public dmrs_pucch_estimator_factory return spy; } + std::unique_ptr create_formats3_4() override + { + std::unique_ptr spy = std::make_unique(); + formats3_4_entries.push_back(spy.get()); + return spy; + } + std::vector& get_format1_entries() { return format1_entries; } std::vector& get_format2_entries() { return format2_entries; } + std::vector& get_formats3_4_entries() { return formats3_4_entries; } private: std::vector format1_entries; std::vector format2_entries; + std::vector formats3_4_entries; }; } // namespace srsran \ No newline at end of file From b013e5baa4f1db44fe8f3e3408f24d227b4922a3 Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Fri, 8 Nov 2024 12:13:28 +0100 Subject: [PATCH 12/26] phy: refactor dmrs pucch estimator into composition --- .../phy/upper/pucch_orthogonal_sequence.h | 1 + .../signal_processors/dmrs_pucch_estimator.h | 133 +++++++++++++ .../signal_processors/dmrs_pucch_processor.h | 85 --------- .../signal_processor_factories.h | 8 +- .../channel_processors/pucch/factories.cpp | 3 +- .../pucch/pucch_processor_impl.cpp | 35 ++-- .../pucch/pucch_processor_impl.h | 17 +- .../upper/signal_processors/CMakeLists.txt | 6 +- ...l.cpp => dmrs_pucch_estimator_format1.cpp} | 39 ++-- ..._impl.h => dmrs_pucch_estimator_format1.h} | 27 +-- ...l.cpp => dmrs_pucch_estimator_format2.cpp} | 36 ++-- ..._impl.h => dmrs_pucch_estimator_format2.h} | 23 ++- .../dmrs_pucch_estimator_formats_3_4.cpp | 175 ++++++++++++++++++ .../pucch/dmrs_pucch_estimator_formats_3_4.h | 106 +++++++++++ .../pucch/dmrs_pucch_estimator_impl.h | 80 ++++++++ .../dmrs_pucch_processor_formats_3_4_impl.cpp | 136 -------------- .../dmrs_pucch_processor_formats_3_4_impl.h | 75 -------- .../signal_processor_factories.cpp | 34 ++-- .../pucch_processor_format1_unittest.cpp | 16 +- .../upper/signal_processors/CMakeLists.txt | 6 +- ...test.cpp => dmrs_pucch_estimator_test.cpp} | 121 +++++++----- .../dmrs_pucch_estimator_test_data.h | 70 +++++++ .../dmrs_pucch_estimator_test_data.tar.gz | 3 + .../dmrs_pucch_estimator_test_doubles.h | 122 ++++++++++++ .../dmrs_pucch_processor_test_data.h | 64 ------- .../dmrs_pucch_processor_test_data.tar.gz | 3 - .../dmrs_pucch_processor_test_doubles.h | 79 -------- 27 files changed, 884 insertions(+), 619 deletions(-) create mode 100644 include/srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h delete mode 100644 include/srsran/phy/upper/signal_processors/dmrs_pucch_processor.h rename lib/phy/upper/signal_processors/pucch/{dmrs_pucch_processor_format1_impl.cpp => dmrs_pucch_estimator_format1.cpp} (80%) rename lib/phy/upper/signal_processors/pucch/{dmrs_pucch_processor_format1_impl.h => dmrs_pucch_estimator_format1.h} (64%) rename lib/phy/upper/signal_processors/pucch/{dmrs_pucch_processor_format2_impl.cpp => dmrs_pucch_estimator_format2.cpp} (65%) rename lib/phy/upper/signal_processors/pucch/{dmrs_pucch_processor_format2_impl.h => dmrs_pucch_estimator_format2.h} (63%) create mode 100644 lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats_3_4.cpp create mode 100644 lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats_3_4.h create mode 100644 lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_impl.h delete mode 100644 lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.cpp delete mode 100644 lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.h rename tests/unittests/phy/upper/signal_processors/{dmrs_pucch_processor_test.cpp => dmrs_pucch_estimator_test.cpp} (53%) create mode 100644 tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test_data.h create mode 100644 tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test_data.tar.gz create mode 100644 tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test_doubles.h delete mode 100644 tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.h delete mode 100644 tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.tar.gz delete mode 100644 tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_doubles.h diff --git a/include/srsran/phy/upper/pucch_orthogonal_sequence.h b/include/srsran/phy/upper/pucch_orthogonal_sequence.h index 3905343616..55cc961aed 100644 --- a/include/srsran/phy/upper/pucch_orthogonal_sequence.h +++ b/include/srsran/phy/upper/pucch_orthogonal_sequence.h @@ -15,6 +15,7 @@ #include "srsran/adt/complex.h" #include "srsran/adt/span.h" +#include "srsran/phy/constants.h" #include "srsran/ran/pucch/pucch_constants.h" #include "srsran/support/math/math_utils.h" #include "srsran/support/srsran_assert.h" diff --git a/include/srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h b/include/srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h new file mode 100644 index 0000000000..6de2642612 --- /dev/null +++ b/include/srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h @@ -0,0 +1,133 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "srsran/adt/static_vector.h" +#include "srsran/phy/upper/channel_estimation.h" +#include "srsran/phy/upper/dmrs_mapping.h" +#include "srsran/ran/cyclic_prefix.h" +#include "srsran/ran/pucch/pucch_mapping.h" +#include "srsran/ran/slot_point.h" + +namespace srsran { + +class resource_grid_reader; + +/// Describes a DM-RS for PUCCH estimator interface. +class dmrs_pucch_estimator +{ +public: + /// Collects common parameters for all PUCCH Formats. + struct common_configuration { + /// Slot timing and numerology. + slot_point slot; + /// Cyclic Prefix. + cyclic_prefix cp; + /// Group and sequence hopping configuration. + pucch_group_hopping group_hopping; + /// Start symbol index, see TS38.331 PUCCH-Resource IE. + unsigned start_symbol_index; + /// Number of symbols, see TS38.331 PUCCH-Resource IE. + unsigned nof_symbols; + /// Start PRB index, see TS38.331 PUCCH-Resource IE. + unsigned starting_prb; + /// \brief Index of first PRB of the second hop if intra-slot frequency hopping is enabled, empty otherwise. + /// \remark see PUCCH-Resource IE in TS38.331. + std::optional second_hop_prb; + /// \brief Parameter \f$n_{ID}\f$ in TS38.211 Section 6.3.2.2.2. + /// + /// Higher layer parameter \e hoppingID if configured (Cell-specific scrambling ID for group hopping and sequence + /// hopping), otherwise the physical cell identifier. + unsigned n_id; + /// Port indexes the PUCCH transmission is mapped onto. + static_vector ports; + }; + + /// Collects specific PUCCH Format 1 parameters. + struct format1_configuration : common_configuration { + /// Initial cyclic shift, used by Formats 0 and 1 as defined in TS38.211 Section 6.3.2.2.2. + unsigned initial_cyclic_shift; + /// Orthogonal Cover Code Index. + unsigned time_domain_occ; + }; + + /// Collects specific PUCCH Format 2 parameters. + struct format2_configuration : common_configuration { + /// Number of PRBs, applicable for Formats 2 and 3 (see PUCCH-Resource IE in TS38.331). + unsigned nof_prb; + /// \brief DM-RS scrambling identity, defined in TS38.211 Section 6.4.1.3.2.1. + /// + /// Higher layer parameter \e scramblingID0 in \e DM-RS-UplinkConfig if it is given, otherwise the physical cell + /// identifier. + unsigned n_id_0; + }; + + /// Collects specific PUCCH Format 3 parameters. + struct format3_configuration : common_configuration { + /// Number of PRBs. + unsigned nof_prb; + /// \brief Additional DM-RS flag (true if enabled), indicating two DM-RS symbols per hop. + /// \remark Applicable to PUCCH Formats 3 and 4. + /// \remark See PUCCH-Format-Config IE in TS38.331. + bool additional_dmrs; + }; + + /// Collects specific PUCCH Format 4 parameters. + struct format4_configuration : common_configuration { + /// \brief Additional DM-RS flag (true if enabled), indicating two DM-RS symbols per hop. + /// \remark Applicable to PUCCH Formats 3 and 4. + /// \remark See PUCCH-Format-Config IE in TS38.331. + bool additional_dmrs; + /// Orthogonal Cover Code Index. + unsigned occ_index; + }; + + /// Default destructor. + virtual ~dmrs_pucch_estimator() = default; + + /// \brief Estimates the propagation channel for PUCCH Format 1. + /// + /// \param[out] estimate Channel estimation results. + /// \param[in] grid Received resource grid. + /// \param[in] config PUCCH Format 1 configuration. + /// \note The \c estimate dimensions must be consistent with the \grid dimensions. + virtual void + estimate(channel_estimate& estimate, const resource_grid_reader& grid, const format1_configuration& config) = 0; + + /// \brief Estimates the propagation channel for PUCCH Format 2. + /// + /// \param[out] estimate Channel estimation results. + /// \param[in] grid Received resource grid. + /// \param[in] config PUCCH Format 2 configuration. + /// \note The \c estimate dimensions must be consistent with the \grid dimensions. + virtual void + estimate(channel_estimate& estimate, const resource_grid_reader& grid, const format2_configuration& config) = 0; + + /// \brief Estimates the propagation channel for PUCCH Format 3. + /// + /// \param[out] estimate Channel estimation results. + /// \param[in] grid Received resource grid. + /// \param[in] config PUCCH Format 3 configuration. + /// \note The \c estimate dimensions must be consistent with the \grid dimensions. + virtual void + estimate(channel_estimate& estimate, const resource_grid_reader& grid, const format3_configuration& config) = 0; + + /// \brief Estimates the propagation channel for PUCCH Format 4. + /// + /// \param[out] estimate Channel estimation results. + /// \param[in] grid Received resource grid. + /// \param[in] config PUCCH Format 4 configuration. + /// \note The \c estimate dimensions must be consistent with the \grid dimensions. + virtual void + estimate(channel_estimate& estimate, const resource_grid_reader& grid, const format4_configuration& config) = 0; +}; + +} // namespace srsran diff --git a/include/srsran/phy/upper/signal_processors/dmrs_pucch_processor.h b/include/srsran/phy/upper/signal_processors/dmrs_pucch_processor.h deleted file mode 100644 index 112035f840..0000000000 --- a/include/srsran/phy/upper/signal_processors/dmrs_pucch_processor.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#pragma once - -#include "srsran/adt/static_vector.h" -#include "srsran/phy/upper/channel_estimation.h" -#include "srsran/phy/upper/dmrs_mapping.h" -#include "srsran/ran/cyclic_prefix.h" -#include "srsran/ran/pucch/pucch_mapping.h" -#include "srsran/ran/slot_point.h" - -namespace srsran { - -class resource_grid_reader; - -/// Describes a DM-RS for PUCCH processor interface. -class dmrs_pucch_processor -{ -public: - /// Describes the necessary parameters to generate DM-RS for a PUCCH transmission. - struct config_t { - /// PUCCH format. - pucch_format format; - /// Slot timing and numerology. - slot_point slot; - /// Cyclic Prefix. - cyclic_prefix cp; - /// Group and sequence hopping configuration. - pucch_group_hopping group_hopping; - /// Start symbol index, see TS38.331 PUCCH-Resource IE. - unsigned start_symbol_index; - /// Number of symbols, see TS38.331 PUCCH-Resource IE. - unsigned nof_symbols; - /// Start PRB index, common to all formats (see TS38.331 PUCCH-Resource IE). - unsigned starting_prb; - /// \brief Intra-slot frequency hopping flag (true if enabled), applicable for all PUCCH formats. - /// \remark see PUCCH-Resource IE in TS38.331. - bool intra_slot_hopping; - /// Index of first PRB after PUCCH frequency hopping (see PUCCH-Resource IE in TS38.331). - unsigned second_hop_prb; - /// Number of PRBs, applicable for Formats 2 and 3 (see PUCCH-Resource IE in TS38.331). - unsigned nof_prb; - /// Initial cyclic shift, used by Formats 0 and 1 as defined in TS38.211 Section 6.3.2.2.2. - unsigned initial_cyclic_shift; - /// Orthogonal Cover Code Index, used by Format 1 (see PUCCH-Resource IE in TS38.331). - unsigned time_domain_occ; - /// \brief Additional DM-RS flag (true if enabled), indicating two DM-RS symbols per hop. - /// \remark Applicable to PUCCH Formats 3 and 4. - /// \remark See PUCCH-Format-Config IE in TS38.331. - bool additional_dmrs; - /// \brief Parameter \f$n_{ID}\f$ in TS38.211 Section 6.3.2.2.2. - /// - /// Higher layer parameter \e hoppingID if configured (Cell-specific scrambling ID for group hopping and sequence - /// hopping), otherwise the physical cell identifier. - unsigned n_id; - /// \brief DM-RS scrambling identity, defined in TS38.211 Section 6.4.1.3.2.1. - /// - /// Higher layer parameter \e scramblingID0 in \e DM-RS-UplinkConfig if it is given, otherwise the physical cell - /// identifier. - unsigned n_id_0; - /// Port indexes the PUCCH transmission is mapped onto. - static_vector ports; - }; - - /// Default destructor. - virtual ~dmrs_pucch_processor() = default; - - /// \brief Estimates the PUCCH propagation channel. - /// - /// \param[out] estimate Channel estimation results. - /// \param[in] grid Received resource grid. - /// \param[in] config PUCCH configuration parameters required for channel estimation. - /// \note The \c estimate dimensions must be consistent with the \grid dimensions. - virtual void estimate(channel_estimate& estimate, const resource_grid_reader& grid, const config_t& config) = 0; -}; - -} // namespace srsran diff --git a/include/srsran/phy/upper/signal_processors/signal_processor_factories.h b/include/srsran/phy/upper/signal_processors/signal_processor_factories.h index 0b4754dee2..20e8ada730 100644 --- a/include/srsran/phy/upper/signal_processors/signal_processor_factories.h +++ b/include/srsran/phy/upper/signal_processors/signal_processor_factories.h @@ -7,7 +7,7 @@ #include "srsran/phy/upper/signal_processors/dmrs_pbch_processor.h" #include "srsran/phy/upper/signal_processors/dmrs_pdcch_processor.h" #include "srsran/phy/upper/signal_processors/dmrs_pdsch_processor.h" -#include "srsran/phy/upper/signal_processors/dmrs_pucch_processor.h" +#include "srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h" #include "srsran/phy/upper/signal_processors/dmrs_pusch_estimator.h" #include "srsran/phy/upper/signal_processors/nzp_csi_rs_generator.h" #include "srsran/phy/upper/signal_processors/port_channel_estimator.h" @@ -54,10 +54,8 @@ create_dmrs_pdsch_processor_factory_sw(std::shared_ptr create_format1() = 0; - virtual std::unique_ptr create_format2() = 0; - virtual std::unique_ptr create_formats3_4() = 0; + virtual ~dmrs_pucch_estimator_factory() = default; + virtual std::unique_ptr create() = 0; }; std::shared_ptr diff --git a/lib/phy/upper/channel_processors/pucch/factories.cpp b/lib/phy/upper/channel_processors/pucch/factories.cpp index 122414735c..54105d6e49 100644 --- a/lib/phy/upper/channel_processors/pucch/factories.cpp +++ b/lib/phy/upper/channel_processors/pucch/factories.cpp @@ -101,8 +101,7 @@ class pucch_processor_factory_sw : public pucch_processor_factory std::unique_ptr create() override { return std::make_unique(create_validator(), - dmrs_factory->create_format1(), - dmrs_factory->create_format2(), + dmrs_factory->create(), detector_factory->create(), demodulator_factory->create(), decoder_factory->create(), diff --git a/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.cpp b/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.cpp index e609dd1781..29b21ef502 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.cpp +++ b/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.cpp @@ -65,27 +65,22 @@ pucch_processor_result pucch_processor_impl::process(const resource_grid_reader& srsran_assert(handle_validation(msg, pdu_validator->is_valid(config)), "{}", msg); // Prepare channel estimation. - dmrs_pucch_processor::config_t estimator_config; - estimator_config.format = pucch_format::FORMAT_1; + dmrs_pucch_estimator::format1_configuration estimator_config; estimator_config.slot = config.slot; estimator_config.cp = config.cp; estimator_config.start_symbol_index = config.start_symbol_index; estimator_config.nof_symbols = config.nof_symbols; estimator_config.starting_prb = config.starting_prb + config.bwp_start_rb; - estimator_config.intra_slot_hopping = config.second_hop_prb.has_value(); estimator_config.second_hop_prb = config.second_hop_prb.has_value() - ? (config.second_hop_prb.value() + config.bwp_start_rb) - : estimator_config.starting_prb; + ? std::optional{config.second_hop_prb.value() + config.bwp_start_rb} + : std::nullopt; estimator_config.initial_cyclic_shift = config.initial_cyclic_shift; estimator_config.time_domain_occ = config.time_domain_occ; estimator_config.n_id = config.n_id; estimator_config.ports.assign(config.ports.begin(), config.ports.end()); // Unused channel estimator parameters for this format. - estimator_config.group_hopping = pucch_group_hopping::NEITHER; - estimator_config.nof_prb = 0; - estimator_config.n_id_0 = 0; - estimator_config.additional_dmrs = false; + estimator_config.group_hopping = pucch_group_hopping::NEITHER; // Prepare channel estimate. channel_estimate::channel_estimate_dimensions dims; @@ -97,7 +92,7 @@ pucch_processor_result pucch_processor_impl::process(const resource_grid_reader& estimates.resize(dims); // Perform channel estimation. - channel_estimator_format_1->estimate(estimates, grid, estimator_config); + channel_estimator->estimate(estimates, grid, estimator_config); // Prepare detector configuration. pucch_detector::format1_configuration detector_config; @@ -151,23 +146,19 @@ pucch_processor_result pucch_processor_impl::process(const resource_grid_reader& result.message = pucch_uci_message(pucch_uci_message_config); // Channel estimator configuration. - dmrs_pucch_processor::config_t estimator_config; - estimator_config.format = pucch_format::FORMAT_2; + dmrs_pucch_estimator::format2_configuration estimator_config; estimator_config.slot = config.slot; estimator_config.cp = config.cp; estimator_config.group_hopping = pucch_group_hopping::NEITHER; estimator_config.start_symbol_index = config.start_symbol_index; estimator_config.nof_symbols = config.nof_symbols; estimator_config.starting_prb = config.bwp_start_rb + config.starting_prb; - estimator_config.intra_slot_hopping = config.second_hop_prb.has_value(); - estimator_config.second_hop_prb = evaluate_or(config.second_hop_prb, 0U, std::plus(), config.bwp_start_rb); - - estimator_config.nof_prb = config.nof_prb; - estimator_config.initial_cyclic_shift = 0; - estimator_config.time_domain_occ = 0; - estimator_config.additional_dmrs = false; - estimator_config.n_id = config.n_id; - estimator_config.n_id_0 = config.n_id_0; + estimator_config.second_hop_prb = config.second_hop_prb.has_value() + ? std::optional{config.second_hop_prb.value() + config.bwp_start_rb} + : std::nullopt; + estimator_config.nof_prb = config.nof_prb; + estimator_config.n_id = config.n_id; + estimator_config.n_id_0 = config.n_id_0; estimator_config.ports.assign(config.ports.begin(), config.ports.end()); // Prepare channel estimate. @@ -180,7 +171,7 @@ pucch_processor_result pucch_processor_impl::process(const resource_grid_reader& estimates.resize(dims); // Perform channel estimation. - channel_estimator_format_2->estimate(estimates, grid, estimator_config); + channel_estimator->estimate(estimates, grid, estimator_config); estimates.get_channel_state_information(result.csi); diff --git a/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.h b/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.h index d8495a8021..9c16e66828 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.h +++ b/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.h @@ -15,7 +15,7 @@ #include "srsran/phy/upper/channel_processors/pucch/pucch_detector.h" #include "srsran/phy/upper/channel_processors/pucch/pucch_processor.h" #include "srsran/phy/upper/channel_processors/uci/uci_decoder.h" -#include "srsran/phy/upper/signal_processors/dmrs_pucch_processor.h" +#include "srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h" #include "srsran/ran/pucch/pucch_constants.h" namespace srsran { @@ -85,23 +85,20 @@ class pucch_processor_impl : public pucch_processor /// PUCCH processor constructor. pucch_processor_impl(std::unique_ptr pdu_validator_, - std::unique_ptr channel_estimator_format_1_, - std::unique_ptr channel_estimator_format_2_, + std::unique_ptr channel_estimator_, std::unique_ptr detector_, std::unique_ptr demodulator_, std::unique_ptr decoder_, const channel_estimate::channel_estimate_dimensions& estimates_dimensions) : pdu_validator(std::move(pdu_validator_)), - channel_estimator_format_1(std::move(channel_estimator_format_1_)), - channel_estimator_format_2(std::move(channel_estimator_format_2_)), + channel_estimator(std::move(channel_estimator_)), detector(std::move(detector_)), demodulator(std::move(demodulator_)), decoder(std::move(decoder_)), estimates(estimates_dimensions), max_sizes(estimates_dimensions) { - srsran_assert(channel_estimator_format_1, "Invalid channel estimator for PUCCH Format 1."); - srsran_assert(channel_estimator_format_2, "Invalid channel estimator for PUCCH Format 2."); + srsran_assert(channel_estimator, "Invalid channel estimator."); srsran_assert(detector, "Invalid detector."); srsran_assert(demodulator, "Invalid PUCCH demodulator."); srsran_assert(decoder, "Invalid UCI decoder."); @@ -110,10 +107,8 @@ class pucch_processor_impl : public pucch_processor private: /// PUCCH PDU validator for all formats. std::unique_ptr pdu_validator; - /// Channel estimator for PUCCH Format 1. - std::unique_ptr channel_estimator_format_1; - /// Channel estimator for PUCCH Format 2. - std::unique_ptr channel_estimator_format_2; + /// Channel estimator. + std::unique_ptr channel_estimator; /// PUCCH detector for 1 or 2 bits, using format 0 and 1. std::unique_ptr detector; /// PUCCH demodulator for more than 2 bits, using formats 2, 3 and 4. diff --git a/lib/phy/upper/signal_processors/CMakeLists.txt b/lib/phy/upper/signal_processors/CMakeLists.txt index 221e77371d..1a211ab7e4 100644 --- a/lib/phy/upper/signal_processors/CMakeLists.txt +++ b/lib/phy/upper/signal_processors/CMakeLists.txt @@ -9,9 +9,9 @@ set(SOURCES ptrs/ptrs_pdsch_generator_impl.cpp ptrs/ptrs_pdsch_generator_factory.cpp - pucch/dmrs_pucch_processor_format1_impl.cpp - pucch/dmrs_pucch_processor_format2_impl.cpp - pucch/dmrs_pucch_processor_formats_3_4_impl.cpp + pucch/dmrs_pucch_estimator_format1.cpp + pucch/dmrs_pucch_estimator_format2.cpp + pucch/dmrs_pucch_estimator_formats_3_4.cpp srs/srs_estimator_factory.cpp srs/srs_estimator_generic_impl.cpp srs/srs_validator_generic_impl.cpp diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format1.cpp similarity index 80% rename from lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp rename to lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format1.cpp index 8957f66770..68803b075b 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format1.cpp @@ -8,9 +8,9 @@ * */ -#include "dmrs_pucch_processor_format1_impl.h" -#include "../../../../../include/srsran/phy/upper/pucch_orthogonal_sequence.h" +#include "dmrs_pucch_estimator_format1.h" #include "srsran/phy/upper/pucch_helper.h" +#include "srsran/phy/upper/pucch_orthogonal_sequence.h" #include "srsran/srsvec/sc_prod.h" using namespace srsran; @@ -23,9 +23,9 @@ static const bounded_bitset pucch_format1_dmrs_symb_mask = {true, false, true, false, true, false, true, false, true, false, true, false, true, false}; // Implements TS38.211 Table 6.4.1.3.1.1-1: Number of DM-RS symbols and the corresponding N_PUCCH. -static unsigned dmrs_pucch_symbols(const dmrs_pucch_processor::config_t& config, unsigned m_prime) +static unsigned dmrs_pucch_symbols(const dmrs_pucch_estimator::format1_configuration& config, unsigned m_prime) { - if (config.intra_slot_hopping) { + if (config.second_hop_prb.has_value()) { if (m_prime == 0) { switch (config.nof_symbols) { case 4: @@ -91,8 +91,8 @@ static unsigned dmrs_pucch_symbols(const dmrs_pucch_processor::config_t& config, return 0; } -dmrs_pucch_processor_format1_impl::layer_dmrs_pattern -dmrs_pucch_processor_format1_impl::generate_dmrs_pattern(const config_t& config) +dmrs_pucch_estimator_format1::layer_dmrs_pattern +dmrs_pucch_estimator_format1::generate_dmrs_pattern(const dmrs_pucch_estimator::format1_configuration& config) { layer_dmrs_pattern mask; @@ -103,10 +103,10 @@ dmrs_pucch_processor_format1_impl::generate_dmrs_pattern(const config_t& config) mask.rb_mask.resize(config.starting_prb + 1); mask.rb_mask.set(config.starting_prb); - if (config.intra_slot_hopping) { + if (config.second_hop_prb.has_value()) { // Set second hop PRB allocation. - mask.rb_mask2.resize(config.second_hop_prb + 1); - mask.rb_mask2.set(config.second_hop_prb); + mask.rb_mask2.resize(config.second_hop_prb.value() + 1); + mask.rb_mask2.set(config.second_hop_prb.value()); // Set the hopping symbol index, indicating the start of the second hop. In case of a PUCCH allocation with an odd // number of symbols, the second hop is one symbol larger than the first one. See TS38.211 Table 6.3.2.4.1-1. @@ -123,10 +123,10 @@ dmrs_pucch_processor_format1_impl::generate_dmrs_pattern(const config_t& config) return mask; } -void dmrs_pucch_processor_format1_impl::generate_sequence(span sequence, - const config_t& pucch_config, - const sequence_generation_config& cfg, - unsigned symbol) const +void dmrs_pucch_estimator_format1::generate_sequence(span sequence, + const dmrs_pucch_estimator::format1_configuration& pucch_config, + const sequence_generation_config& cfg, + unsigned symbol) const { // Compute alpha index. unsigned alpha_idx = helper.get_alpha_index( @@ -143,18 +143,16 @@ void dmrs_pucch_processor_format1_impl::generate_sequence(span srsvec::sc_prod(r_uv, w_i_m, sequence); } -void dmrs_pucch_processor_format1_impl::estimate(channel_estimate& estimate, - const resource_grid_reader& grid, - const config_t& config) +void dmrs_pucch_estimator_format1::estimate(channel_estimate& estimate, + const resource_grid_reader& grid, + const dmrs_pucch_estimator::format1_configuration& config) { - srsran_assert(config.nof_prb <= 1, "PUCCH Format 1 occupies a single PRB."); - unsigned nof_rx_ports = config.ports.size(); // Prepare DM-RS symbol buffer dimensions. Recall that PUCCH Format 1 occupies a single PRB. re_measurement_dimensions dims; dims.nof_subc = NRE; - if (config.intra_slot_hopping) { + if (config.second_hop_prb.has_value()) { // Consider the number of DM-RS symbols of both hops. dims.nof_symbols = dmrs_pucch_symbols(config, 0) + dmrs_pucch_symbols(config, 1); } else { @@ -174,7 +172,8 @@ void dmrs_pucch_processor_format1_impl::estimate(channel_estimate& est // Generate DM-RS sequences for even-numbered symbols within the PUCCH allocation, as per TS38.211 // Section 6.4.1.3.1. - for (unsigned i_hop = 0, i_symb = config.start_symbol_index; i_hop < (config.intra_slot_hopping ? 2 : 1); ++i_hop) { + for (unsigned i_hop = 0, i_symb = config.start_symbol_index; i_hop < (config.second_hop_prb.has_value() ? 2 : 1); + ++i_hop) { // Get number of symbols carrying DM-RS in the current hop. unsigned nof_dmrs_symb_hop = dmrs_pucch_symbols(config, i_hop); diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format1.h similarity index 64% rename from lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h rename to lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format1.h index 9be25a761c..84d41c8c2d 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format1.h @@ -12,28 +12,30 @@ #include "srsran/phy/upper/pucch_helper.h" #include "srsran/phy/upper/sequence_generators/low_papr_sequence_collection.h" -#include "srsran/phy/upper/signal_processors/dmrs_pucch_processor.h" +#include "srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h" #include "srsran/phy/upper/signal_processors/port_channel_estimator.h" namespace srsran { /// Generic implementation of a DM-RS channel estimator for PUCCH Format 1. -class dmrs_pucch_processor_format1_impl : public dmrs_pucch_processor +class dmrs_pucch_estimator_format1 { public: using layer_dmrs_pattern = port_channel_estimator::layer_dmrs_pattern; - dmrs_pucch_processor_format1_impl(std::unique_ptr prg_, - std::unique_ptr sequence_collection_, - std::unique_ptr ch_est_) : + dmrs_pucch_estimator_format1(std::unique_ptr prg_, + std::unique_ptr sequence_collection_, + std::unique_ptr ch_est_) : helper(std::move(prg_)), sequence_collection(std::move(sequence_collection_)), ch_estimator(std::move(ch_est_)) { srsran_assert(sequence_collection, "Invalid sequence collection."); srsran_assert(ch_estimator, "Invalid port channel estimator."); } - // See interface for documentation. - void estimate(channel_estimate& ce_, const resource_grid_reader& grid, const config_t& config) override; + /// Estimates the channel of a PUCCH Format 1 transmission. See \ref dmrs_pucch_estimator for more details. + void estimate(channel_estimate& ce_, + const resource_grid_reader& grid, + const dmrs_pucch_estimator::format1_configuration& config); private: pucch_helper helper; @@ -64,16 +66,17 @@ class dmrs_pucch_processor_format1_impl : public dmrs_pucch_processor /// \param[in] pucch_config PUCCH configuration. /// \param[in] gen_config Additional parameters required to calculate the sequences. /// \param[in] symbol OFDM symbol index. - void generate_sequence(span sequence, - const config_t& pucch_config, - const sequence_generation_config& gen_config, - unsigned symbol) const; + void generate_sequence(span sequence, + const dmrs_pucch_estimator::format1_configuration& pucch_config, + const sequence_generation_config& gen_config, + unsigned symbol) const; /// \brief Generates the PUCCH DM-RS allocation pattern. /// /// Implements the PUCCH DM-RS mapping, as described in TS38.211 Section 6.4.1.3.1.2. /// \param[in] config Configuration parameters. /// \return The DM-RS allocation pattern. - static layer_dmrs_pattern generate_dmrs_pattern(const config_t& config); + static layer_dmrs_pattern generate_dmrs_pattern(const dmrs_pucch_estimator::format1_configuration& config); }; + } // namespace srsran diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format2_impl.cpp b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format2.cpp similarity index 65% rename from lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format2_impl.cpp rename to lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format2.cpp index 51b876a730..0850e637f2 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format2_impl.cpp +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format2.cpp @@ -8,7 +8,7 @@ * */ -#include "dmrs_pucch_processor_format2_impl.h" +#include "dmrs_pucch_estimator_format2.h" #include "srsran/ran/pucch/pucch_constants.h" using namespace srsran; @@ -19,7 +19,8 @@ using namespace srsran; static const bounded_bitset format2_prb_re_mask = {false, true, false, false, true, false, false, true, false, false, true, false}; -unsigned dmrs_pucch_processor_format2_impl::c_init(unsigned symbol, const config_t& config) +unsigned dmrs_pucch_estimator_format2::c_init(unsigned symbol, + const dmrs_pucch_estimator::format2_configuration& config) { uint64_t n_slot = config.slot.slot_index(); uint64_t n_id = config.n_id_0; @@ -27,10 +28,10 @@ unsigned dmrs_pucch_processor_format2_impl::c_init(unsigned symbol, const config return ((get_nsymb_per_slot(config.cp) * n_slot + symbol + 1) * (2 * n_id + 1) * pow2(17) + 2 * n_id) % pow2(31); } -void dmrs_pucch_processor_format2_impl::generate_sequence(span sequence, - unsigned symbol, - unsigned starting_prb, - const config_t& config) +void dmrs_pucch_estimator_format2::generate_sequence(span sequence, + unsigned symbol, + unsigned starting_prb, + const dmrs_pucch_estimator::format2_configuration& config) { // Initialize pseudo-random generator. prg->init(c_init(symbol, config)); @@ -42,8 +43,8 @@ void dmrs_pucch_processor_format2_impl::generate_sequence(span sequen prg->generate(sequence, M_SQRT1_2); } -dmrs_pucch_processor_format2_impl::layer_dmrs_pattern -dmrs_pucch_processor_format2_impl::generate_dmrs_pattern(const config_t& config) +dmrs_pucch_estimator_format2::layer_dmrs_pattern +dmrs_pucch_estimator_format2::generate_dmrs_pattern(const dmrs_pucch_estimator::format2_configuration& config) { layer_dmrs_pattern mask; @@ -54,10 +55,10 @@ dmrs_pucch_processor_format2_impl::generate_dmrs_pattern(const config_t& config) mask.rb_mask.resize(config.starting_prb + config.nof_prb); mask.rb_mask.fill(config.starting_prb, config.starting_prb + config.nof_prb, true); - if (config.intra_slot_hopping) { + if (config.second_hop_prb.has_value()) { // Set second hop PRB allocation. - mask.rb_mask2.resize(config.second_hop_prb + config.nof_prb); - mask.rb_mask2.fill(config.second_hop_prb, config.second_hop_prb + config.nof_prb, true); + mask.rb_mask2.resize(config.second_hop_prb.value() + config.nof_prb); + mask.rb_mask2.fill(config.second_hop_prb.value(), config.second_hop_prb.value() + config.nof_prb, true); // Set the hopping symbol index, indicating the start of the second hop. Recall that PUCCH Format 2 occupies a // maximum of 2 OFDM symbols. @@ -71,11 +72,11 @@ dmrs_pucch_processor_format2_impl::generate_dmrs_pattern(const config_t& config) return mask; } -void dmrs_pucch_processor_format2_impl::estimate(channel_estimate& estimate, - const resource_grid_reader& grid, - const config_t& config) +void dmrs_pucch_estimator_format2::estimate(channel_estimate& estimate, + const resource_grid_reader& grid, + const dmrs_pucch_estimator::format2_configuration& config) { - srsran_assert((!config.intra_slot_hopping || (config.nof_symbols > pucch_constants::FORMAT2_MIN_NSYMB)), + srsran_assert((!config.second_hop_prb.has_value() || (config.nof_symbols > pucch_constants::FORMAT2_MIN_NSYMB)), "Frequency hopping requires {} OFDM symbols.", pucch_constants::FORMAT2_MAX_NSYMB); @@ -95,8 +96,9 @@ void dmrs_pucch_processor_format2_impl::estimate(channel_estimate& est // For each symbol carrying DM-RS (up to 2 symbols maximum). for (unsigned i_symb = i_symb_start, i_dmrs_symb = 0; i_symb != i_symb_end; ++i_symb, ++i_dmrs_symb) { // Generate sequence. - unsigned prb_start = - ((i_symb != i_symb_start) && (config.intra_slot_hopping)) ? config.second_hop_prb : config.starting_prb; + unsigned prb_start = ((i_symb != i_symb_start) && (config.second_hop_prb.has_value())) + ? config.second_hop_prb.value() + : config.starting_prb; generate_sequence(temp_symbols.get_symbol(i_dmrs_symb, 0), i_symb, prb_start, config); } diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format2_impl.h b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format2.h similarity index 63% rename from lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format2_impl.h rename to lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format2.h index 3eef347090..ba6bcc5028 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format2_impl.h +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format2.h @@ -11,26 +11,29 @@ #pragma once #include "srsran/phy/upper/sequence_generators/pseudo_random_generator.h" -#include "srsran/phy/upper/signal_processors/dmrs_pucch_processor.h" +#include "srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h" #include "srsran/phy/upper/signal_processors/port_channel_estimator.h" namespace srsran { /// Generic implementation of a DM-RS channel estimator for PUCCH Format 2. -class dmrs_pucch_processor_format2_impl : public dmrs_pucch_processor +class dmrs_pucch_estimator_format2 { public: using layer_dmrs_pattern = port_channel_estimator::layer_dmrs_pattern; - dmrs_pucch_processor_format2_impl(std::unique_ptr prg_, - std::unique_ptr ch_est_) : + dmrs_pucch_estimator_format2(std::unique_ptr prg_, + std::unique_ptr ch_est_) : prg(std::move(prg_)), ch_estimator(std::move(ch_est_)) { srsran_assert(prg, "Invalid pseudo random generator."); srsran_assert(ch_estimator, "Invalid port channel estimator."); } - void estimate(channel_estimate& ce_, const resource_grid_reader& grid, const config_t& config) override; + /// Estimates the channel of a PUCCH Format 2 transmission. See \ref dmrs_pucch_estimator for more details. + void estimate(channel_estimate& ce_, + const resource_grid_reader& grid, + const dmrs_pucch_estimator::format2_configuration& config); private: /// Number of DM-RS RE per Resource Block. @@ -48,7 +51,7 @@ class dmrs_pucch_processor_format2_impl : public dmrs_pucch_processor /// \param[in] symbol OFDM symbol index. /// \param[in] config PUCCH configuration parameters. /// \return The initial pseudo-random state. - static unsigned c_init(unsigned symbol, const config_t& config); + static unsigned c_init(unsigned symbol, const dmrs_pucch_estimator::format2_configuration& config); /// \brief Generates a DM-RS sequence according to TS38.211 Section 6.4.1.3.2.1. /// @@ -56,13 +59,17 @@ class dmrs_pucch_processor_format2_impl : public dmrs_pucch_processor /// \param[in] symbol Symbol index. /// \param[in] start_prb Index of first PRB allocated for DM-RS in the current symbol. /// \param[in] config Required parameters to calculate the sequences. - void generate_sequence(span sequence, unsigned symbol, unsigned start_prb, const config_t& config); + void generate_sequence(span sequence, + unsigned symbol, + unsigned start_prb, + const dmrs_pucch_estimator::format2_configuration& config); /// \brief Generates the PUCCH DM-RS allocation pattern. /// /// Implements the PUCCH DM-RS mapping, as described in TS38.211 Section 6.4.1.3.2.2. /// \param[in] config Configuration parameters. /// \return The DM-RS allocation pattern. - static layer_dmrs_pattern generate_dmrs_pattern(const config_t& config); + static layer_dmrs_pattern generate_dmrs_pattern(const dmrs_pucch_estimator::format2_configuration& config); }; + } // namespace srsran diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats_3_4.cpp b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats_3_4.cpp new file mode 100644 index 0000000000..93b5754f7c --- /dev/null +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats_3_4.cpp @@ -0,0 +1,175 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "dmrs_pucch_estimator_formats_3_4.h" +#include "srsran/phy/upper/pucch_formats_3_4_helpers.h" +#include "srsran/ran/pucch/pucch_constants.h" + +using namespace srsran; + +void dmrs_pucch_estimator_formats_3_4::generate_sequence(span sequence, + const estimate_config& config, + unsigned u, + unsigned v, + unsigned symbol) +{ + unsigned m_0 = 0; + // m_0 for PUCCH Format 4 is selected according to TS38.211 Table 6.4.1.3.3.1-1. + switch (config.occ_index) { + case 0: + m_0 = 0; + break; + case 1: + m_0 = 6; + break; + case 2: + m_0 = 3; + break; + case 3: + m_0 = 9; + break; + default: + break; + } + + // Compute alpha index. + unsigned alpha_idx = helper.get_alpha_index(config.slot, config.cp, config.n_id, symbol, m_0, 0); + + // Generate the r_uv sequence. + low_papr_generator->generate(sequence, u, v, alpha_idx, NRE); +} + +dmrs_pucch_estimator_formats_3_4::layer_dmrs_pattern +dmrs_pucch_estimator_formats_3_4::generate_dmrs_pattern(const estimate_config& config) +{ + layer_dmrs_pattern mask; + + // All RE within the PRB are allocated to DM-RS. + mask.re_pattern = ~bounded_bitset(NRE); + + // Set PRB allocation. + mask.rb_mask.resize(config.starting_prb + config.nof_prb); + mask.rb_mask.fill(config.starting_prb, config.starting_prb + config.nof_prb, true); + + if (config.second_hop_prb.has_value()) { + // Set second hop PRB allocation. + mask.rb_mask2.resize(config.second_hop_prb.value() + config.nof_prb); + mask.rb_mask2.fill(config.second_hop_prb.value(), config.second_hop_prb.value() + config.nof_prb, true); + + // Set the hopping symbol index, indicating the start of the second hop. In case of a PUCCH allocation with an odd + // number of symbols, the second hop is one symbol larger than the first one. + mask.hopping_symbol_index = config.start_symbol_index + (config.nof_symbols / 2); + } + + symbol_slot_mask dmrs_symb_mask = get_pucch_formats_3_4_dmrs_symbol_mask( + config.nof_symbols, config.second_hop_prb.has_value(), config.additional_dmrs); + + mask.symbols.resize(get_nsymb_per_slot(config.cp)); + dmrs_symb_mask.for_each(0, config.nof_symbols, [&mask, &config](unsigned bitpos) { + mask.symbols.set(config.start_symbol_index + bitpos); + }); + + return mask; +} + +void dmrs_pucch_estimator_formats_3_4::estimate(channel_estimate& estimate, + const resource_grid_reader& grid, + const estimate_config& config) +{ + symbol_slot_mask dmrs_symb_mask = get_pucch_formats_3_4_dmrs_symbol_mask( + config.nof_symbols, config.second_hop_prb.has_value(), config.additional_dmrs); + + // Prepare DM-RS symbol buffer dimensions. + re_measurement_dimensions dims; + dims.nof_subc = config.nof_prb * NRE; + dims.nof_symbols = dmrs_symb_mask.count(); + dims.nof_slices = pucch_constants::MAX_LAYERS; + + // Resize DM-RS symbol buffer. + temp_symbols.resize(dims); + + unsigned u, v; + helper.compute_group_sequence(config.group_hopping, config.n_id, u, v); + + unsigned i_symb_start = config.start_symbol_index; + unsigned i_symb_end = config.start_symbol_index + config.nof_symbols; + + unsigned i_dmrs_symb = 0; + for (unsigned i_symb = i_symb_start; i_symb != i_symb_end; ++i_symb) { + // For each symbol carrying DM-RS. + if (!dmrs_symb_mask.test(i_symb - config.start_symbol_index)) { + continue; + } + + generate_sequence(temp_symbols.get_symbol(i_dmrs_symb, 0), config, u, v, i_symb); + ++i_dmrs_symb; + } + + // Prepare channel estimator configuration. + port_channel_estimator::configuration est_cfg; + est_cfg.scs = to_subcarrier_spacing(config.slot.numerology()); + est_cfg.cp = config.cp; + est_cfg.first_symbol = config.start_symbol_index; + est_cfg.nof_symbols = config.nof_symbols; + est_cfg.dmrs_pattern = {generate_dmrs_pattern(config)}; + est_cfg.rx_ports = config.ports; + est_cfg.scaling = 1.0F; + + unsigned nof_rx_ports = config.ports.size(); + + // Perform estimation for each receive port. + for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { + ch_estimator->compute(estimate, grid, i_port, temp_symbols, est_cfg); + } +} + +void dmrs_pucch_estimator_formats_3_4::estimate(channel_estimate& ch_estimate, + const resource_grid_reader& grid, + const dmrs_pucch_estimator::format3_configuration& config) +{ + estimate_config est_cfg = { + .slot = config.slot, + .cp = config.cp, + .group_hopping = config.group_hopping, + .n_id = config.n_id, + .nof_prb = config.nof_prb, + .nof_symbols = config.nof_symbols, + .starting_prb = config.starting_prb, + .second_hop_prb = config.second_hop_prb, + .start_symbol_index = config.start_symbol_index, + .additional_dmrs = config.additional_dmrs, + .occ_index = 0, + .ports = config.ports, + }; + + estimate(ch_estimate, grid, est_cfg); +} + +void dmrs_pucch_estimator_formats_3_4::estimate(channel_estimate& ch_estimate, + const resource_grid_reader& grid, + const dmrs_pucch_estimator::format4_configuration& config) +{ + estimate_config est_cfg = { + .slot = config.slot, + .cp = config.cp, + .group_hopping = config.group_hopping, + .n_id = config.n_id, + .nof_prb = 1, + .nof_symbols = config.nof_symbols, + .starting_prb = config.starting_prb, + .second_hop_prb = config.second_hop_prb, + .start_symbol_index = config.start_symbol_index, + .additional_dmrs = config.additional_dmrs, + .occ_index = config.occ_index, + .ports = config.ports, + }; + + estimate(ch_estimate, grid, est_cfg); +} diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats_3_4.h b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats_3_4.h new file mode 100644 index 0000000000..ac690b4656 --- /dev/null +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats_3_4.h @@ -0,0 +1,106 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "srsran/phy/upper/pucch_helper.h" +#include "srsran/phy/upper/sequence_generators/low_papr_sequence_generator.h" +#include "srsran/phy/upper/sequence_generators/pseudo_random_generator.h" +#include "srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h" +#include "srsran/phy/upper/signal_processors/port_channel_estimator.h" + +namespace srsran { + +/// Generic implementation of a DM-RS channel estimator for PUCCH Formats 3 and 4. +class dmrs_pucch_estimator_formats_3_4 +{ +public: + using layer_dmrs_pattern = port_channel_estimator::layer_dmrs_pattern; + + dmrs_pucch_estimator_formats_3_4(std::unique_ptr prg_, + std::unique_ptr low_papr_generator_, + std::unique_ptr ch_est_) : + helper(std::move(prg_)), low_papr_generator(std::move(low_papr_generator_)), ch_estimator(std::move(ch_est_)) + { + srsran_assert(low_papr_generator, "Invalid sequence generator."); + srsran_assert(ch_estimator, "Invalid port channel estimator."); + } + + /// Estimates the channel of a PUCCH Format 3 transmission. See \ref dmrs_pucch_estimator for more details. + void estimate(channel_estimate& ce_, + const resource_grid_reader& grid, + const dmrs_pucch_estimator::format3_configuration& config); + + /// Estimates the channel of a PUCCH Format 4 transmission. See \ref dmrs_pucch_estimator for more details. + void estimate(channel_estimate& ce_, + const resource_grid_reader& grid, + const dmrs_pucch_estimator::format4_configuration& config); + +private: + pucch_helper helper; + + /// PUCCH Formats 3 and 4 implementation expects pre-generated sequence collection on instantiation. + std::unique_ptr low_papr_generator; + /// Antenna port channel estimator. + std::unique_ptr ch_estimator; + + /// Buffer for DM-RS symbols. + dmrs_symbol_list temp_symbols; + + /// Common configuration parameters for PUCCH Formats 3 and 4. + struct estimate_config { + // Slot timing and numerology. + slot_point slot; + // Cyclic Prefix. + cyclic_prefix cp; + // Group and sequence hopping configuration. + pucch_group_hopping group_hopping; + // Parameter \f$n_{ID}\f$ in TS38.211 Section 6.3.2.2.2. + unsigned n_id; + // Number of PRBs. + unsigned nof_prb; + // Number of OFDM symbols assigned to resource. + unsigned nof_symbols; + // Start PRB index. + unsigned starting_prb; + // Index of first PRB of the second hop if intra-slot frequency hopping is enabled, empty otherwise. + std::optional second_hop_prb; + // Start symbol index. + unsigned start_symbol_index; + // Additional DM-RS flag. + bool additional_dmrs; + // Orthogonal Cover Code. + unsigned occ_index; + // Port indexes the PUCCH transmission is mapped onto. + const static_vector& ports; + }; + + /// Performs the actual channel estimation of a PUCCH Format 3 or Format 4 transmission. + void estimate(channel_estimate& ce_, const resource_grid_reader& grid, const estimate_config& config); + + /// \brief Generates a DM-RS sequence according to TS38.211 Section 6.4.1.3.2.1. + /// + /// \param[out] sequence Sequence destination. + /// \param[in] config Required parameters to calculate the sequences. + /// \param[in] u Sequence group. + /// \param[in] v Sequence number. + /// \param[in] symbol Symbol index. + void generate_sequence(span sequence, const estimate_config& config, unsigned u, unsigned v, unsigned symbol); + + /// \brief Generates the PUCCH DM-RS allocation pattern. + /// + /// Implements the PUCCH DM-RS mapping, as described in TS38.211 Section 6.4.1.3.3.2. + /// \param[in] config Number of PRBs. + /// + /// \return The DM-RS allocation pattern. + static layer_dmrs_pattern generate_dmrs_pattern(const estimate_config& config); +}; + +} // namespace srsran diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_impl.h b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_impl.h new file mode 100644 index 0000000000..0383741785 --- /dev/null +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_impl.h @@ -0,0 +1,80 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +/// \file +/// \brief DM-RS PUCCH estimator implementation declaration. + +#pragma once + +#include "dmrs_pucch_estimator_format1.h" +#include "dmrs_pucch_estimator_format2.h" +#include "dmrs_pucch_estimator_formats_3_4.h" +#include "srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h" + +namespace srsran { + +/// DM-RS PUCCH estimator implementation. +class dmrs_pucch_estimator_impl : public dmrs_pucch_estimator +{ +public: + /// Constructor: sets up internal components and acquires their ownership. + /// \param[in] estimator_format1_ PUCCH Format 1 DM-RS estimator. + /// \param[in] estimator_format2_ PUCCH Format 1 DM-RS estimator. + /// \param[in] estimator_formats_3_4_ PUCCH Format 3 and Format 4 DM-RS estimator. + dmrs_pucch_estimator_impl(std::unique_ptr estimator_format1_, + std::unique_ptr estimator_format2_, + std::unique_ptr estimator_formats_3_4_) : + estimator_format1(std::move(estimator_format1_)), + estimator_format2(std::move(estimator_format2_)), + estimator_formats_3_4(std::move(estimator_formats_3_4_)) + { + srsran_assert(estimator_format1, "Invalid pointer to dmrs_pucch_estimator_format1 object."); + srsran_assert(estimator_format2, "Invalid pointer to dmrs_pucch_estimator_format2 object."); + srsran_assert(estimator_formats_3_4, "Invalid pointer to dmrs_pucch_estimator_formats_3_4 object."); + } + + // See interface for the documentation. + void + estimate(channel_estimate& estimate, const resource_grid_reader& grid, const format1_configuration& config) override + { + estimator_format1->estimate(estimate, grid, config); + } + + // See interface for the documentation. + void + estimate(channel_estimate& estimate, const resource_grid_reader& grid, const format2_configuration& config) override + { + estimator_format2->estimate(estimate, grid, config); + } + + // See interface for the documentation. + void + estimate(channel_estimate& estimate, const resource_grid_reader& grid, const format3_configuration& config) override + { + estimator_formats_3_4->estimate(estimate, grid, config); + } + + // See interface for the documentation. + void + estimate(channel_estimate& estimate, const resource_grid_reader& grid, const format4_configuration& config) override + { + estimator_formats_3_4->estimate(estimate, grid, config); + } + +private: + /// PUCCH DM-RS estimator Format 1 component. + std::unique_ptr estimator_format1; + /// PUCCH DM-RS estimator Format 1 component. + std::unique_ptr estimator_format2; + /// PUCCH DM-RS estimator Format 3 and Format 4 component. + std::unique_ptr estimator_formats_3_4; +}; + +} // namespace srsran diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.cpp b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.cpp deleted file mode 100644 index bc58fe2701..0000000000 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#include "dmrs_pucch_processor_formats_3_4_impl.h" -#include "srsran/phy/upper/pucch_formats_3_4_helpers.h" -#include "srsran/ran/pucch/pucch_constants.h" - -using namespace srsran; - -void dmrs_pucch_processor_formats_3_4_impl::generate_sequence(span sequence, - const config_t& config, - const sequence_generation_config& gen_config, - unsigned symbol) -{ - unsigned m_0 = 0; - // m_0 for PUCCH Format 4 is selected according to TS38.211 Table 6.4.1.3.3.1-1. - if (config.format == pucch_format::FORMAT_4) { - switch (config.time_domain_occ) { - case 0: - m_0 = 0; - break; - case 1: - m_0 = 6; - break; - case 2: - m_0 = 3; - break; - case 3: - m_0 = 9; - break; - default: - break; - } - } - - // Compute alpha index. - unsigned alpha_idx = helper.get_alpha_index(config.slot, config.cp, config.n_id, symbol, m_0, 0); - - // Generate the r_uv sequence. - low_papr_generator->generate(sequence, gen_config.u, gen_config.v, alpha_idx, NRE); -} - -dmrs_pucch_processor_formats_3_4_impl::layer_dmrs_pattern -dmrs_pucch_processor_formats_3_4_impl::generate_dmrs_pattern(const config_t& config) -{ - layer_dmrs_pattern mask; - - // All RE within the PRB are allocated to DM-RS. - mask.re_pattern = ~bounded_bitset(NRE); - - // Set PRB allocation. - mask.rb_mask.resize(config.starting_prb + config.nof_prb); - mask.rb_mask.fill(config.starting_prb, config.starting_prb + config.nof_prb, true); - - if (config.intra_slot_hopping) { - // Set second hop PRB allocation. - mask.rb_mask2.resize(config.second_hop_prb + config.nof_prb); - mask.rb_mask2.fill(config.second_hop_prb, config.second_hop_prb + config.nof_prb, true); - - // Set the hopping symbol index, indicating the start of the second hop. In case of a PUCCH allocation with an odd - // number of symbols, the second hop is one symbol larger than the first one. - mask.hopping_symbol_index = config.start_symbol_index + (config.nof_symbols / 2); - } - - symbol_slot_mask dmrs_symb_mask = - get_pucch_formats_3_4_dmrs_symbol_mask(config.nof_symbols, config.intra_slot_hopping, config.additional_dmrs); - - mask.symbols.resize(get_nsymb_per_slot(config.cp)); - dmrs_symb_mask.for_each(0, config.nof_symbols, [&mask, &config](unsigned bitpos) { - mask.symbols.set(config.start_symbol_index + bitpos); - }); - - return mask; -} - -void dmrs_pucch_processor_formats_3_4_impl::estimate(channel_estimate& estimate, - const resource_grid_reader& grid, - const config_t& config) -{ - srsran_assert(!((config.format == pucch_format::FORMAT_4) && (config.nof_prb > 1)), - "PUCCH Format 4 occupies a single PRB"); - - unsigned nof_rx_ports = config.ports.size(); - - symbol_slot_mask dmrs_symb_mask = - get_pucch_formats_3_4_dmrs_symbol_mask(config.nof_symbols, config.intra_slot_hopping, config.additional_dmrs); - - // Prepare DM-RS symbol buffer dimensions. - re_measurement_dimensions dims; - dims.nof_subc = config.nof_prb * NRE; - dims.nof_symbols = dmrs_symb_mask.count(); - dims.nof_slices = pucch_constants::MAX_LAYERS; - - // Resize DM-RS symbol buffer. - temp_symbols.resize(dims); - - unsigned u, v; - helper.compute_group_sequence(config.group_hopping, config.n_id, u, v); - - unsigned i_symb_start = config.start_symbol_index; - unsigned i_symb_end = config.start_symbol_index + config.nof_symbols; - - unsigned i_dmrs_symb = 0; - for (unsigned i_symb = i_symb_start; i_symb != i_symb_end; ++i_symb) { - // For each symbol carrying DM-RS. - if (!dmrs_symb_mask.test(i_symb - config.start_symbol_index)) { - continue; - } - - sequence_generation_config cfg = {.u = u, .v = v}; - generate_sequence(temp_symbols.get_symbol(i_dmrs_symb, 0), config, cfg, i_symb); - ++i_dmrs_symb; - } - - // Prepare channel estimator configuration. - port_channel_estimator::configuration est_cfg; - est_cfg.scs = to_subcarrier_spacing(config.slot.numerology()); - est_cfg.cp = config.cp; - est_cfg.first_symbol = config.start_symbol_index; - est_cfg.nof_symbols = config.nof_symbols; - est_cfg.dmrs_pattern = {generate_dmrs_pattern(config)}; - est_cfg.rx_ports = config.ports; - est_cfg.scaling = 1.0F; - - // Perform estimation for each receive port. - for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { - ch_estimator->compute(estimate, grid, i_port, temp_symbols, est_cfg); - } -} \ No newline at end of file diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.h b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.h deleted file mode 100644 index 1233b015f8..0000000000 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_formats_3_4_impl.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#pragma once - -#include "srsran/phy/upper/pucch_helper.h" -#include "srsran/phy/upper/sequence_generators/low_papr_sequence_generator.h" -#include "srsran/phy/upper/sequence_generators/pseudo_random_generator.h" -#include "srsran/phy/upper/signal_processors/dmrs_pucch_processor.h" -#include "srsran/phy/upper/signal_processors/port_channel_estimator.h" - -namespace srsran { - -/// Generic implementation of a DM-RS channel estimator for PUCCH Formats 3 and 4. -class dmrs_pucch_processor_formats_3_4_impl : public dmrs_pucch_processor -{ -public: - using layer_dmrs_pattern = port_channel_estimator::layer_dmrs_pattern; - - dmrs_pucch_processor_formats_3_4_impl(std::unique_ptr prg_, - std::unique_ptr low_papr_generator_, - std::unique_ptr ch_est_) : - helper(std::move(prg_)), low_papr_generator(std::move(low_papr_generator_)), ch_estimator(std::move(ch_est_)) - { - srsran_assert(low_papr_generator, "Invalid sequence generator."); - srsran_assert(ch_estimator, "Invalid port channel estimator."); - } - - void estimate(channel_estimate& ce_, const resource_grid_reader& grid, const config_t& config) override; - -private: - pucch_helper helper; - - /// PUCCH Formats 3 and 4 implementation expects pre-generated sequence collection on instantiation. - std::unique_ptr low_papr_generator; - /// Antenna port channel estimator. - std::unique_ptr ch_estimator; - - /// Buffer for DM-RS symbols. - dmrs_symbol_list temp_symbols; - - /// Holds DM-RS sequence generation parameters used in TS38.211 Section 6.4.1.3.3.1. - struct sequence_generation_config { - // Sequence group. - unsigned u; - // Sequence number. - unsigned v; - }; - - /// \brief Generates a DM-RS sequence according to TS38.211 Section 6.4.1.3.2.1. - /// - /// \param[out] sequence Sequence destination. - /// \param[in] symbol Symbol index. - /// \param[in] gen_config Additional parameters required to calculate the sequences. - /// \param[in] config Required parameters to calculate the sequences. - void generate_sequence(span sequence, - const config_t& config, - const sequence_generation_config& gen_config, - unsigned symbol); - - /// \brief Generates the PUCCH DM-RS allocation pattern. - /// - /// Implements the PUCCH DM-RS mapping, as described in TS38.211 Section 6.4.1.3.3.2. - /// \param[in] config Configuration parameters. - /// \return The DM-RS allocation pattern. - static layer_dmrs_pattern generate_dmrs_pattern(const config_t& config); -}; -} // namespace srsran diff --git a/lib/phy/upper/signal_processors/signal_processor_factories.cpp b/lib/phy/upper/signal_processors/signal_processor_factories.cpp index 7addaad2e2..94f5b1949e 100644 --- a/lib/phy/upper/signal_processors/signal_processor_factories.cpp +++ b/lib/phy/upper/signal_processors/signal_processor_factories.cpp @@ -17,16 +17,15 @@ #include "nzp_csi_rs_generator_pool.h" #include "port_channel_estimator_average_impl.h" #include "pss_processor_impl.h" -#include "pucch/dmrs_pucch_processor_format1_impl.h" -#include "pucch/dmrs_pucch_processor_format2_impl.h" -#include "pucch/dmrs_pucch_processor_formats_3_4_impl.h" +#include "pucch/dmrs_pucch_estimator_format1.h" +#include "pucch/dmrs_pucch_estimator_format2.h" +#include "pucch/dmrs_pucch_estimator_formats_3_4.h" +#include "pucch/dmrs_pucch_estimator_impl.h" #include "sss_processor_impl.h" - #include "srsran/phy/support/support_factories.h" #include "srsran/phy/support/support_formatters.h" #include "srsran/phy/support/time_alignment_estimator/time_alignment_estimator_factories.h" #include "srsran/phy/upper/signal_processors/signal_processor_formatters.h" -#include "srsran/ran/pucch/pucch_constants.h" using namespace srsran; @@ -109,7 +108,7 @@ class dmrs_pucch_estimator_sw_factory : public dmrs_pucch_estimator_factory srsran_assert(ch_estimator_factory, "Invalid channel estimator factory."); } - std::unique_ptr create_format1() override + std::unique_ptr create() override { // Prepare DM-RS for PUCCH Format 1 low PAPR sequence parameters. unsigned m = 1; @@ -119,24 +118,23 @@ class dmrs_pucch_estimator_sw_factory : public dmrs_pucch_estimator_factory return TWOPI * static_cast(n++) / static_cast(NRE); }); - return std::make_unique( + std::unique_ptr estimator_format1 = std::make_unique( prg_factory->create(), lpc_factory->create(m, delta, alphas), ch_estimator_factory->create(port_channel_estimator_fd_smoothing_strategy::mean, /*compensate_cfo =*/false)); - } - std::unique_ptr create_format2() override - { - return std::make_unique( + std::unique_ptr estimator_format2 = std::make_unique( prg_factory->create(), ch_estimator_factory->create(port_channel_estimator_fd_smoothing_strategy::filter)); - } - std::unique_ptr create_formats3_4() override - { - return std::make_unique( - prg_factory->create(), - lpg_factory->create(), - ch_estimator_factory->create(port_channel_estimator_fd_smoothing_strategy::mean, /*compensate_cfo =*/false)); + std::unique_ptr estimator_formats_3_4 = + std::make_unique( + prg_factory->create(), + lpg_factory->create(), + ch_estimator_factory->create(port_channel_estimator_fd_smoothing_strategy::mean, + /*compensate_cfo =*/false)); + + return std::make_unique( + std::move(estimator_format1), std::move(estimator_format2), std::move(estimator_formats_3_4)); } private: diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format1_unittest.cpp b/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format1_unittest.cpp index fda7916673..2b1fc4d00b 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format1_unittest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_processor_format1_unittest.cpp @@ -9,7 +9,7 @@ */ #include "../../../support/resource_grid_test_doubles.h" -#include "../../signal_processors/dmrs_pucch_processor_test_doubles.h" +#include "../../signal_processors/dmrs_pucch_estimator_test_doubles.h" #include "../uci/uci_decoder_test_doubles.h" #include "pucch_detector_test_doubles.h" #include "srsran/ran/pucch/pucch_constants.h" @@ -91,7 +91,7 @@ class PucchProcessorFormat1Fixture : public ::testing::TestWithParam ASSERT_NE(validator, nullptr) << "Cannot create PUCCH processor validator."; // Select spies. - dmrs_spy = dmrs_factory_spy->get_format1_entries().back(); + dmrs_spy = dmrs_factory_spy->get_entries().back(); ASSERT_NE(dmrs_spy, nullptr); detector_spy = detector_factory_spy->get_entries().back(); @@ -146,7 +146,7 @@ class PucchProcessorFormat1Fixture : public ::testing::TestWithParam std::unique_ptr processor; std::unique_ptr validator; - dmrs_pucch_processor_spy* dmrs_spy; + dmrs_pucch_estimator_spy* dmrs_spy; pucch_detector_spy* detector_spy; }; @@ -169,25 +169,21 @@ TEST_P(PucchProcessorFormat1Fixture, UnitTest) const pucch_processor_result result = processor->process(grid, config); // Verify channel estimator configuration. - ASSERT_EQ(dmrs_spy->get_entries().size(), 1); - const dmrs_pucch_processor_spy::entry_t& dmrs_entry = dmrs_spy->get_entries().front(); - ASSERT_EQ(dmrs_entry.config.format, pucch_format::FORMAT_1); + ASSERT_EQ(dmrs_spy->get_format1_entries().size(), 1); + const dmrs_pucch_estimator_spy::entry_format1_t& dmrs_entry = dmrs_spy->get_format1_entries().front(); ASSERT_EQ(dmrs_entry.config.slot, config.slot); ASSERT_EQ(dmrs_entry.config.cp, config.cp); ASSERT_EQ(dmrs_entry.config.group_hopping, pucch_group_hopping::NEITHER); ASSERT_EQ(dmrs_entry.config.start_symbol_index, config.start_symbol_index); ASSERT_EQ(dmrs_entry.config.nof_symbols, config.nof_symbols); ASSERT_EQ(dmrs_entry.config.starting_prb, config.starting_prb + config.bwp_start_rb); - ASSERT_EQ(dmrs_entry.config.intra_slot_hopping, config.second_hop_prb.has_value()); + ASSERT_EQ(dmrs_entry.config.second_hop_prb.has_value(), config.second_hop_prb.has_value()); if (config.second_hop_prb.has_value()) { ASSERT_EQ(dmrs_entry.config.second_hop_prb, config.second_hop_prb.value() + config.bwp_start_rb); } - ASSERT_EQ(dmrs_entry.config.nof_prb, 0); ASSERT_EQ(dmrs_entry.config.initial_cyclic_shift, config.initial_cyclic_shift); ASSERT_EQ(dmrs_entry.config.time_domain_occ, config.time_domain_occ); - ASSERT_EQ(dmrs_entry.config.additional_dmrs, false); ASSERT_EQ(dmrs_entry.config.n_id, config.n_id); - ASSERT_EQ(dmrs_entry.config.n_id_0, 0); ASSERT_EQ(span(dmrs_entry.config.ports), span(config.ports)); // Verify PUCCH detector. diff --git a/tests/unittests/phy/upper/signal_processors/CMakeLists.txt b/tests/unittests/phy/upper/signal_processors/CMakeLists.txt index a4f0ce2766..b2941c3fb0 100644 --- a/tests/unittests/phy/upper/signal_processors/CMakeLists.txt +++ b/tests/unittests/phy/upper/signal_processors/CMakeLists.txt @@ -44,9 +44,9 @@ if (USE_PHY_TESTVECTORS) target_link_libraries(dmrs_pdsch_processor_test srsran_signal_processors srsvec srsran_sequence_generators srslog srsran_channel_precoder) add_test_vector(dmrs_pdsch_processor_test dmrs_pdsch_processor_test_data.tar.gz "") - add_executable(dmrs_pucch_processor_test dmrs_pucch_processor_test.cpp) - target_link_libraries(dmrs_pucch_processor_test srsran_signal_processors srsvec srsran_sequence_generators srslog srsran_support gtest gtest_main) - add_test_vector(dmrs_pucch_processor_test dmrs_pucch_processor_test_data.tar.gz "") + add_executable(dmrs_pucch_estimator_test dmrs_pucch_estimator_test.cpp) + target_link_libraries(dmrs_pucch_estimator_test srsran_signal_processors srsvec srsran_sequence_generators srslog srsran_support gtest gtest_main) + add_test_vector(dmrs_pucch_estimator_test dmrs_pucch_estimator_test_data.tar.gz "") add_executable(dmrs_pusch_estimator_test dmrs_pusch_estimator_test.cpp) target_link_libraries(dmrs_pusch_estimator_test diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test.cpp b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test.cpp similarity index 53% rename from tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test.cpp rename to tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test.cpp index 5e750493c1..6973f99045 100644 --- a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test.cpp +++ b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test.cpp @@ -9,7 +9,7 @@ */ #include "../../support/resource_grid_test_doubles.h" -#include "dmrs_pucch_processor_test_data.h" +#include "dmrs_pucch_estimator_test_data.h" #include "srsran/phy/upper/signal_processors/signal_processor_factories.h" #include "fmt/ostream.h" #include @@ -18,25 +18,67 @@ using namespace srsran; namespace srsran { -std::ostream& operator<<(std::ostream& os, const test_case_t& test_case) +std::ostream& operator<<(std::ostream& os, const dmrs_pucch_estimator::common_configuration& cc) { - const dmrs_pucch_processor::config_t& cc = test_case.config; fmt::print(os, - "PUCCH Format {}, SCS {} kHz, intra-slot fr. hop. {}, shift {}, occ {}, +DM-RS {}, port {}", - cc.format, + "SCS {} kHz, intra-slot fr. hop. {}, port {}", 15U * (1U << cc.slot.numerology()), - (cc.intra_slot_hopping ? "ON" : "OFF"), - cc.initial_cyclic_shift, - cc.time_domain_occ, - (cc.additional_dmrs ? "ON" : "OFF"), + (cc.second_hop_prb.has_value() ? "ON" : "OFF"), cc.ports[0]); return os; } + +std::ostream& operator<<(std::ostream& os, const dmrs_pucch_estimator::format1_configuration& config) +{ + fmt::print(os, + "PUCCH Format 1 {}, CP {}, OCC {}", + static_cast(config), + config.initial_cyclic_shift, + config.time_domain_occ); + return os; +} + +std::ostream& operator<<(std::ostream& os, const dmrs_pucch_estimator::format2_configuration& config) +{ + fmt::print(os, + "PUCCH Format 2 {}, PRBs {}, nid0 {}", + static_cast(config), + config.nof_prb, + config.n_id_0); + return os; +} + +std::ostream& operator<<(std::ostream& os, const dmrs_pucch_estimator::format3_configuration& config) +{ + fmt::print(os, + "PUCCH Format 3 {}, PRBs {}, +DMRS {}", + static_cast(config), + config.nof_prb, + (config.additional_dmrs ? "ON" : "OFF")); + return os; +} + +std::ostream& operator<<(std::ostream& os, const dmrs_pucch_estimator::format4_configuration& config) +{ + fmt::print(os, + "PUCCH Format 4 {}, +DMRS {}, OCC {}", + static_cast(config), + (config.additional_dmrs ? "ON" : "OFF"), + config.occ_index); + return os; +} + +std::ostream& operator<<(std::ostream& os, const test_case_t& test_case) +{ + std::visit([&os](const auto& config) { fmt::print(os, "{}", config); }, test_case.config); + return os; +} + } // namespace srsran namespace { -class DmrsPucchProcessorFixture : public ::testing::TestWithParam +class DmrsPucchEstimatorFixture : public ::testing::TestWithParam { protected: // The factory only needs to be created once. @@ -84,33 +126,17 @@ class DmrsPucchProcessorFixture : public ::testing::TestWithParam // Check the factory again, since ASSERT_* is not fatal in SetUpTestSuite in old googletest releases. ASSERT_NE(estimator_factory, nullptr) << "Cannot create PUCCH estimator factory."; - const test_case_t& test_case = GetParam(); - // Create DMRS-PUCCH processor. - switch (test_case.config.format) { - case pucch_format::FORMAT_1: - dmrs_pucch = estimator_factory->create_format1(); - break; - case pucch_format::FORMAT_2: - dmrs_pucch = estimator_factory->create_format2(); - break; - case pucch_format::FORMAT_3: - case pucch_format::FORMAT_4: - dmrs_pucch = estimator_factory->create_formats3_4(); - case pucch_format::FORMAT_0: - case pucch_format::NOF_FORMATS: - default: - break; - } - ASSERT_NE(dmrs_pucch, nullptr) << "Cannot create PUCCH processor."; + dmrs_pucch = estimator_factory->create(); + ASSERT_NE(dmrs_pucch, nullptr) << "Cannot create PUCCH estimator."; } static std::shared_ptr estimator_factory; - std::unique_ptr dmrs_pucch = nullptr; + std::unique_ptr dmrs_pucch = nullptr; }; -std::shared_ptr DmrsPucchProcessorFixture::estimator_factory = nullptr; +std::shared_ptr DmrsPucchEstimatorFixture::estimator_factory = nullptr; -TEST_P(DmrsPucchProcessorFixture, DmrsPucchProcessorTest) +TEST_P(DmrsPucchEstimatorFixture, DmrsPucchEstimatorTest) { // Fixed BW const unsigned nof_prb = 52; @@ -124,21 +150,24 @@ TEST_P(DmrsPucchProcessorFixture, DmrsPucchProcessorTest) resource_grid_reader_spy grid; grid.write(testvector_symbols); - // Object to store channel estimation results - channel_estimate::channel_estimate_dimensions ch_est_dims = {}; - ch_est_dims.nof_prb = nof_prb; - ch_est_dims.nof_symbols = get_nsymb_per_slot(test_case.config.cp); - ch_est_dims.nof_tx_layers = 1; - ch_est_dims.nof_rx_ports = 1; - channel_estimate estimate(ch_est_dims); - - // Estimate channel - dmrs_pucch->estimate(estimate, grid, test_case.config); - - ASSERT_NEAR(estimate.get_noise_variance(0), 0, 1e-2) << "Expected an ideal channel!"; + std::visit( + [this, &grid](const auto& config) { + // Object to store channel estimation results + channel_estimate::channel_estimate_dimensions ch_est_dims = {}; + ch_est_dims.nof_prb = nof_prb; + ch_est_dims.nof_symbols = get_nsymb_per_slot(config.cp); + ch_est_dims.nof_tx_layers = 1; + ch_est_dims.nof_rx_ports = 1; + channel_estimate estimate(ch_est_dims); + + dmrs_pucch->estimate(estimate, grid, config); + + ASSERT_NEAR(estimate.get_noise_variance(0), 0, 1e-2) << "Expected an ideal channel!"; + }, + test_case.config); } -INSTANTIATE_TEST_SUITE_P(DmrsPucchProcessorSuite, - DmrsPucchProcessorFixture, - ::testing::ValuesIn(dmrs_pucch_processor_test_data)); +INSTANTIATE_TEST_SUITE_P(DmrsPucchEstimatorSuite, + DmrsPucchEstimatorFixture, + ::testing::ValuesIn(dmrs_pucch_estimator_test_data)); } // namespace \ No newline at end of file diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test_data.h b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test_data.h new file mode 100644 index 0000000000..3d5b9f77a4 --- /dev/null +++ b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test_data.h @@ -0,0 +1,70 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +// This file was generated using the following MATLAB class on 07-11-2024 (seed 0): +// + "srsPUCCHdmrsUnittest.m" + +#include "../../support/resource_grid_test_doubles.h" +#include "srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h" +#include "srsran/support/file_vector.h" +#include + +namespace srsran { + +using estimator_config = std::variant; + +struct test_case_t { + estimator_config config; + file_vector symbols; +}; + +static const std::vector dmrs_pucch_estimator_test_data = { + // clang-format off + {dmrs_pucch_estimator::format1_configuration{{{0, 0}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 5, 8, 37, {}, 608, {3}}, 2, 2}, {"test_data/dmrs_pucch_estimator_test_output0.dat"}}, + {dmrs_pucch_estimator::format1_configuration{{{0, 5}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 14, 13, {}, 451, {1}}, 11, 1}, {"test_data/dmrs_pucch_estimator_test_output1.dat"}}, + {dmrs_pucch_estimator::format1_configuration{{{0, 3}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 7, 4, 9, {18}, 122, {0}}, 7, 0}, {"test_data/dmrs_pucch_estimator_test_output2.dat"}}, + {dmrs_pucch_estimator::format1_configuration{{{0, 6}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 14, 1, {39}, 447, {3}}, 7, 2}, {"test_data/dmrs_pucch_estimator_test_output3.dat"}}, + {dmrs_pucch_estimator::format2_configuration{{{0, 8}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 3, 1, 29, {}, 871, {3}}, 9, 871}, {"test_data/dmrs_pucch_estimator_test_output4.dat"}}, + {dmrs_pucch_estimator::format2_configuration{{{0, 4}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 1, 2, 51, {}, 771, {1}}, 1, 771}, {"test_data/dmrs_pucch_estimator_test_output5.dat"}}, + {dmrs_pucch_estimator::format2_configuration{{{0, 8}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 9, 2, 48, {27}, 98, {7}}, 1, 98}, {"test_data/dmrs_pucch_estimator_test_output6.dat"}}, + {dmrs_pucch_estimator::format2_configuration{{{0, 8}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 2, 7, {12}, 745, {7}}, 4, 745}, {"test_data/dmrs_pucch_estimator_test_output7.dat"}}, + {dmrs_pucch_estimator::format3_configuration{{{0, 6}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 14, 21, {}, 173, {7}}, 16, true}, {"test_data/dmrs_pucch_estimator_test_output8.dat"}}, + {dmrs_pucch_estimator::format3_configuration{{{0, 7}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 1, 11, 12, {}, 332, {2}}, 4, true}, {"test_data/dmrs_pucch_estimator_test_output9.dat"}}, + {dmrs_pucch_estimator::format3_configuration{{{0, 7}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 7, 4, 30, {43}, 634, {4}}, 8, false}, {"test_data/dmrs_pucch_estimator_test_output10.dat"}}, + {dmrs_pucch_estimator::format3_configuration{{{0, 3}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 2, 5, 21, {35}, 555, {7}}, 3, true}, {"test_data/dmrs_pucch_estimator_test_output11.dat"}}, + {dmrs_pucch_estimator::format4_configuration{{{0, 0}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 3, 4, 40, {}, 970, {6}}, true, 0}, {"test_data/dmrs_pucch_estimator_test_output12.dat"}}, + {dmrs_pucch_estimator::format4_configuration{{{0, 4}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 13, 9, {}, 395, {4}}, false, 0}, {"test_data/dmrs_pucch_estimator_test_output13.dat"}}, + {dmrs_pucch_estimator::format4_configuration{{{0, 4}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 5, 4, 5, {27}, 931, {1}}, false, 0}, {"test_data/dmrs_pucch_estimator_test_output14.dat"}}, + {dmrs_pucch_estimator::format4_configuration{{{0, 9}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 5, 4, 20, {7}, 698, {5}}, true, 1}, {"test_data/dmrs_pucch_estimator_test_output15.dat"}}, + {dmrs_pucch_estimator::format1_configuration{{{1, 7}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 1, 10, 37, {}, 293, {7}}, 11, 4}, {"test_data/dmrs_pucch_estimator_test_output16.dat"}}, + {dmrs_pucch_estimator::format1_configuration{{{1, 2}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 4, 8, 43, {}, 243, {5}}, 7, 3}, {"test_data/dmrs_pucch_estimator_test_output17.dat"}}, + {dmrs_pucch_estimator::format1_configuration{{{1, 6}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 4, 7, 28, {18}, 280, {4}}, 11, 0}, {"test_data/dmrs_pucch_estimator_test_output18.dat"}}, + {dmrs_pucch_estimator::format1_configuration{{{1, 15}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 14, 36, {43}, 691, {3}}, 5, 0}, {"test_data/dmrs_pucch_estimator_test_output19.dat"}}, + {dmrs_pucch_estimator::format2_configuration{{{1, 14}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 2, 1, 18, {}, 31, {7}}, 11, 31}, {"test_data/dmrs_pucch_estimator_test_output20.dat"}}, + {dmrs_pucch_estimator::format2_configuration{{{1, 14}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 5, 1, 34, {}, 642, {4}}, 1, 642}, {"test_data/dmrs_pucch_estimator_test_output21.dat"}}, + {dmrs_pucch_estimator::format2_configuration{{{1, 4}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 10, 2, 14, {26}, 360, {5}}, 12, 360}, {"test_data/dmrs_pucch_estimator_test_output22.dat"}}, + {dmrs_pucch_estimator::format2_configuration{{{1, 11}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 4, 2, 26, {12}, 407, {2}}, 8, 407}, {"test_data/dmrs_pucch_estimator_test_output23.dat"}}, + {dmrs_pucch_estimator::format3_configuration{{{1, 19}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 2, 10, 9, {}, 39, {0}}, 10, true}, {"test_data/dmrs_pucch_estimator_test_output24.dat"}}, + {dmrs_pucch_estimator::format3_configuration{{{1, 16}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 3, 6, 50, {}, 21, {0}}, 2, true}, {"test_data/dmrs_pucch_estimator_test_output25.dat"}}, + {dmrs_pucch_estimator::format3_configuration{{{1, 5}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 13, 18, {22}, 459, {2}}, 2, true}, {"test_data/dmrs_pucch_estimator_test_output26.dat"}}, + {dmrs_pucch_estimator::format3_configuration{{{1, 0}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 2, 11, 41, {1}, 959, {2}}, 8, true}, {"test_data/dmrs_pucch_estimator_test_output27.dat"}}, + {dmrs_pucch_estimator::format4_configuration{{{1, 3}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 10, 45, {}, 859, {5}}, true, 1}, {"test_data/dmrs_pucch_estimator_test_output28.dat"}}, + {dmrs_pucch_estimator::format4_configuration{{{1, 14}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 1, 10, 24, {}, 260, {6}}, false, 2}, {"test_data/dmrs_pucch_estimator_test_output29.dat"}}, + {dmrs_pucch_estimator::format4_configuration{{{1, 9}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 11, 40, {14}, 302, {2}}, true, 0}, {"test_data/dmrs_pucch_estimator_test_output30.dat"}}, + {dmrs_pucch_estimator::format4_configuration{{{1, 16}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 14, 45, {32}, 652, {7}}, true, 1}, {"test_data/dmrs_pucch_estimator_test_output31.dat"}}, + // clang-format on +}; + +} // namespace srsran diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test_data.tar.gz b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test_data.tar.gz new file mode 100644 index 0000000000..32856fd7cd --- /dev/null +++ b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test_data.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9c587a766efb1c8bc035d4b18cb02da934c33e012c3d5c90deec651cb300df99 +size 17808 diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test_doubles.h b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test_doubles.h new file mode 100644 index 0000000000..59ab169506 --- /dev/null +++ b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_estimator_test_doubles.h @@ -0,0 +1,122 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "../../phy_test_utils.h" +#include "srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h" +#include "srsran/phy/upper/signal_processors/signal_processor_factories.h" + +namespace srsran { + +class dmrs_pucch_estimator_spy : public dmrs_pucch_estimator +{ +public: + struct entry_format1_t { + const channel_estimate* estimate; + const resource_grid_reader* grid; + format1_configuration config; + }; + + struct entry_format2_t { + const channel_estimate* estimate; + const resource_grid_reader* grid; + format2_configuration config; + }; + + struct entry_format3_t { + const channel_estimate* estimate; + const resource_grid_reader* grid; + format3_configuration config; + }; + + struct entry_format4_t { + const channel_estimate* estimate; + const resource_grid_reader* grid; + format4_configuration config; + }; + + void + estimate(channel_estimate& estimate, const resource_grid_reader& grid, const format1_configuration& config) override + { + format1_entries.emplace_back(); + entry_format1_t& entry = format1_entries.back(); + entry.estimate = &estimate; + entry.grid = &grid; + entry.config = config; + } + + void + estimate(channel_estimate& estimate, const resource_grid_reader& grid, const format2_configuration& config) override + { + format2_entries.emplace_back(); + entry_format2_t& entry = format2_entries.back(); + entry.estimate = &estimate; + entry.grid = &grid; + entry.config = config; + } + + void + estimate(channel_estimate& estimate, const resource_grid_reader& grid, const format3_configuration& config) override + { + format3_entries.emplace_back(); + entry_format3_t& entry = format3_entries.back(); + entry.estimate = &estimate; + entry.grid = &grid; + entry.config = config; + } + + void + estimate(channel_estimate& estimate, const resource_grid_reader& grid, const format4_configuration& config) override + { + format4_entries.emplace_back(); + entry_format4_t& entry = format4_entries.back(); + entry.estimate = &estimate; + entry.grid = &grid; + entry.config = config; + } + + const std::vector& get_format1_entries() const { return format1_entries; } + const std::vector& get_format2_entries() const { return format2_entries; } + const std::vector& get_format3_entries() const { return format3_entries; } + const std::vector& get_format4_entries() const { return format4_entries; } + + void clear() + { + format1_entries.clear(); + format2_entries.clear(); + format3_entries.clear(); + format4_entries.clear(); + } + +private: + std::vector format1_entries; + std::vector format2_entries; + std::vector format3_entries; + std::vector format4_entries; +}; + +class dmrs_pucch_estimator_factory_spy : public dmrs_pucch_estimator_factory +{ +public: + std::unique_ptr create() override + { + std::unique_ptr spy = std::make_unique(); + entries.push_back(spy.get()); + return spy; + } + + std::vector& get_entries() { return entries; } + +private: + std::vector entries; +}; + +} // namespace srsran diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.h b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.h deleted file mode 100644 index 3c770a2fc3..0000000000 --- a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#pragma once - -// This file was generated using the following MATLAB class on 07-11-2024 (seed 0): -// + "srsPUCCHdmrsUnittest.m" - -#include "../../support/resource_grid_test_doubles.h" -#include "srsran/phy/upper/signal_processors/dmrs_pucch_processor.h" -#include "srsran/support/file_vector.h" - -namespace srsran { - -struct test_case_t { - dmrs_pucch_processor::config_t config; - file_vector symbols; -}; - -static const std::vector dmrs_pucch_processor_test_data = { - // clang-format off - {{pucch_format::FORMAT_1, {0, 0}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 5, 8, 37, false, 0, 1, 2, 2, false, 608, 608, {3}}, {"test_data/dmrs_pucch_processor_test_output0.dat"}}, - {{pucch_format::FORMAT_1, {0, 5}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 14, 13, false, 0, 1, 11, 1, false, 451, 451, {1}}, {"test_data/dmrs_pucch_processor_test_output1.dat"}}, - {{pucch_format::FORMAT_1, {0, 3}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 7, 4, 9, true, 18, 1, 7, 0, false, 122, 122, {0}}, {"test_data/dmrs_pucch_processor_test_output2.dat"}}, - {{pucch_format::FORMAT_1, {0, 6}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 14, 1, true, 39, 1, 7, 2, false, 447, 447, {3}}, {"test_data/dmrs_pucch_processor_test_output3.dat"}}, - {{pucch_format::FORMAT_2, {0, 8}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 3, 1, 29, false, 0, 9, 7, 0, false, 871, 871, {3}}, {"test_data/dmrs_pucch_processor_test_output4.dat"}}, - {{pucch_format::FORMAT_2, {0, 4}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 1, 2, 51, false, 0, 1, 9, 0, false, 771, 771, {1}}, {"test_data/dmrs_pucch_processor_test_output5.dat"}}, - {{pucch_format::FORMAT_2, {0, 8}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 9, 2, 48, true, 27, 1, 0, 0, false, 98, 98, {7}}, {"test_data/dmrs_pucch_processor_test_output6.dat"}}, - {{pucch_format::FORMAT_2, {0, 8}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 2, 7, true, 12, 4, 7, 0, false, 745, 745, {7}}, {"test_data/dmrs_pucch_processor_test_output7.dat"}}, - {{pucch_format::FORMAT_3, {0, 6}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 14, 21, false, 0, 16, 4, 0, true, 173, 173, {7}}, {"test_data/dmrs_pucch_processor_test_output8.dat"}}, - {{pucch_format::FORMAT_3, {0, 7}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 1, 11, 12, false, 0, 4, 7, 0, true, 332, 332, {2}}, {"test_data/dmrs_pucch_processor_test_output9.dat"}}, - {{pucch_format::FORMAT_3, {0, 7}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 7, 4, 30, true, 43, 8, 6, 0, false, 634, 634, {4}}, {"test_data/dmrs_pucch_processor_test_output10.dat"}}, - {{pucch_format::FORMAT_3, {0, 3}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 2, 5, 21, true, 35, 3, 5, 0, true, 555, 555, {7}}, {"test_data/dmrs_pucch_processor_test_output11.dat"}}, - {{pucch_format::FORMAT_4, {0, 0}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 3, 4, 40, false, 0, 1, 11, 0, true, 970, 970, {6}}, {"test_data/dmrs_pucch_processor_test_output12.dat"}}, - {{pucch_format::FORMAT_4, {0, 4}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 13, 9, false, 0, 1, 2, 0, false, 395, 395, {4}}, {"test_data/dmrs_pucch_processor_test_output13.dat"}}, - {{pucch_format::FORMAT_4, {0, 4}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 5, 4, 5, true, 27, 1, 10, 0, false, 931, 931, {1}}, {"test_data/dmrs_pucch_processor_test_output14.dat"}}, - {{pucch_format::FORMAT_4, {0, 9}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 5, 4, 20, true, 7, 1, 1, 1, true, 698, 698, {5}}, {"test_data/dmrs_pucch_processor_test_output15.dat"}}, - {{pucch_format::FORMAT_1, {1, 7}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 1, 10, 37, false, 0, 1, 11, 4, false, 293, 293, {7}}, {"test_data/dmrs_pucch_processor_test_output16.dat"}}, - {{pucch_format::FORMAT_1, {1, 2}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 4, 8, 43, false, 0, 1, 7, 3, false, 243, 243, {5}}, {"test_data/dmrs_pucch_processor_test_output17.dat"}}, - {{pucch_format::FORMAT_1, {1, 6}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 4, 7, 28, true, 18, 1, 11, 0, false, 280, 280, {4}}, {"test_data/dmrs_pucch_processor_test_output18.dat"}}, - {{pucch_format::FORMAT_1, {1, 15}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 14, 36, true, 43, 1, 5, 0, false, 691, 691, {3}}, {"test_data/dmrs_pucch_processor_test_output19.dat"}}, - {{pucch_format::FORMAT_2, {1, 14}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 2, 1, 18, false, 0, 11, 0, 0, false, 31, 31, {7}}, {"test_data/dmrs_pucch_processor_test_output20.dat"}}, - {{pucch_format::FORMAT_2, {1, 14}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 5, 1, 34, false, 0, 1, 7, 0, false, 642, 642, {4}}, {"test_data/dmrs_pucch_processor_test_output21.dat"}}, - {{pucch_format::FORMAT_2, {1, 4}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 10, 2, 14, true, 26, 12, 10, 0, false, 360, 360, {5}}, {"test_data/dmrs_pucch_processor_test_output22.dat"}}, - {{pucch_format::FORMAT_2, {1, 11}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 4, 2, 26, true, 12, 8, 9, 0, false, 407, 407, {2}}, {"test_data/dmrs_pucch_processor_test_output23.dat"}}, - {{pucch_format::FORMAT_3, {1, 19}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 2, 10, 9, false, 0, 10, 11, 0, true, 39, 39, {0}}, {"test_data/dmrs_pucch_processor_test_output24.dat"}}, - {{pucch_format::FORMAT_3, {1, 16}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 3, 6, 50, false, 0, 2, 1, 0, true, 21, 21, {0}}, {"test_data/dmrs_pucch_processor_test_output25.dat"}}, - {{pucch_format::FORMAT_3, {1, 5}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 13, 18, true, 22, 2, 1, 0, true, 459, 459, {2}}, {"test_data/dmrs_pucch_processor_test_output26.dat"}}, - {{pucch_format::FORMAT_3, {1, 0}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 2, 11, 41, true, 1, 8, 8, 0, true, 959, 959, {2}}, {"test_data/dmrs_pucch_processor_test_output27.dat"}}, - {{pucch_format::FORMAT_4, {1, 3}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 10, 45, false, 0, 1, 8, 1, true, 859, 859, {5}}, {"test_data/dmrs_pucch_processor_test_output28.dat"}}, - {{pucch_format::FORMAT_4, {1, 14}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 1, 10, 24, false, 0, 1, 5, 2, false, 260, 260, {6}}, {"test_data/dmrs_pucch_processor_test_output29.dat"}}, - {{pucch_format::FORMAT_4, {1, 9}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 11, 40, true, 14, 1, 9, 0, true, 302, 302, {2}}, {"test_data/dmrs_pucch_processor_test_output30.dat"}}, - {{pucch_format::FORMAT_4, {1, 16}, cyclic_prefix::NORMAL, pucch_group_hopping::NEITHER, 0, 14, 45, true, 32, 1, 7, 1, true, 652, 652, {7}}, {"test_data/dmrs_pucch_processor_test_output31.dat"}}, - // clang-format on -}; - -} // namespace srsran diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.tar.gz b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.tar.gz deleted file mode 100644 index 93d81e8542..0000000000 --- a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_data.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4ee50257ffd22058fbf14963f3a7b58348c911fb17a4684bf443d3df554634a2 -size 17774 diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_doubles.h b/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_doubles.h deleted file mode 100644 index 608450802d..0000000000 --- a/tests/unittests/phy/upper/signal_processors/dmrs_pucch_processor_test_doubles.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#pragma once - -#include "../../phy_test_utils.h" -#include "srsran/phy/upper/signal_processors/dmrs_pucch_processor.h" -#include "srsran/phy/upper/signal_processors/signal_processor_factories.h" - -namespace srsran { - -class dmrs_pucch_processor_spy : public dmrs_pucch_processor -{ -public: - struct entry_t { - const channel_estimate* estimate; - const resource_grid_reader* grid; - config_t config; - }; - - void estimate(channel_estimate& estimate, const resource_grid_reader& grid, const config_t& config) override - { - entries.emplace_back(); - entry_t& entry = entries.back(); - entry.estimate = &estimate; - entry.grid = &grid; - entry.config = config; - } - - const std::vector& get_entries() const { return entries; } - - void clear() { entries.clear(); } - -private: - std::vector entries; -}; - -class dmrs_pucch_estimator_factory_spy : public dmrs_pucch_estimator_factory -{ -public: - std::unique_ptr create_format1() override - { - std::unique_ptr spy = std::make_unique(); - format1_entries.push_back(spy.get()); - return spy; - } - - std::unique_ptr create_format2() override - { - std::unique_ptr spy = std::make_unique(); - format2_entries.push_back(spy.get()); - return spy; - } - - std::unique_ptr create_formats3_4() override - { - std::unique_ptr spy = std::make_unique(); - formats3_4_entries.push_back(spy.get()); - return spy; - } - - std::vector& get_format1_entries() { return format1_entries; } - std::vector& get_format2_entries() { return format2_entries; } - std::vector& get_formats3_4_entries() { return formats3_4_entries; } - -private: - std::vector format1_entries; - std::vector format2_entries; - std::vector formats3_4_entries; -}; - -} // namespace srsran \ No newline at end of file From 452c83848b6c87bb3aa79a1dad1204b50864bc55 Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Mon, 11 Nov 2024 10:14:35 +0100 Subject: [PATCH 13/26] phy: review dmrs pucch estimator --- .../pusch/pusch_processor.h | 2 +- ...4_helpers.h => pucch_formats3_4_helpers.h} | 2 +- include/srsran/phy/upper/pucch_helper.h | 12 ++-- .../signal_processors/dmrs_pucch_estimator.h | 8 +-- .../pucch/pucch_demodulator_format3.cpp | 4 +- .../pucch/pucch_demodulator_format4.cpp | 4 +- .../pucch/pucch_detector_format0.cpp | 4 +- .../pucch/pucch_processor_impl.cpp | 28 ++++----- .../pucch/pucch_processor_impl.h | 5 +- .../upper/signal_processors/CMakeLists.txt | 2 +- .../pucch/dmrs_pucch_estimator_format1.cpp | 14 +++-- .../pucch/dmrs_pucch_estimator_format2.cpp | 6 +- ...pp => dmrs_pucch_estimator_formats3_4.cpp} | 63 +++++++++---------- ..._4.h => dmrs_pucch_estimator_formats3_4.h} | 33 +++++----- .../pucch/dmrs_pucch_estimator_impl.h | 20 +++--- .../signal_processor_factories.cpp | 8 +-- .../pucch/pucch_demodulator_format3_test.cpp | 4 +- .../pucch/pucch_demodulator_format4_test.cpp | 4 +- .../dmrs_pucch_estimator_test_doubles.h | 32 +++------- 19 files changed, 119 insertions(+), 136 deletions(-) rename include/srsran/phy/upper/{pucch_formats_3_4_helpers.h => pucch_formats3_4_helpers.h} (99%) rename lib/phy/upper/signal_processors/pucch/{dmrs_pucch_estimator_formats_3_4.cpp => dmrs_pucch_estimator_formats3_4.cpp} (65%) rename lib/phy/upper/signal_processors/pucch/{dmrs_pucch_estimator_formats_3_4.h => dmrs_pucch_estimator_formats3_4.h} (80%) diff --git a/include/srsran/phy/upper/channel_processors/pusch/pusch_processor.h b/include/srsran/phy/upper/channel_processors/pusch/pusch_processor.h index 4fa9678220..f189b9f2ff 100644 --- a/include/srsran/phy/upper/channel_processors/pusch/pusch_processor.h +++ b/include/srsran/phy/upper/channel_processors/pusch/pusch_processor.h @@ -132,7 +132,7 @@ class pusch_processor unsigned n_id; /// Number of transmission layers as per TS38.211 Section 6.3.1.3. unsigned nof_tx_layers; - /// Port indexes the PUSCH reception is mapped to. + /// Port indices the PUSCH reception is mapped to. static_vector rx_ports; /// Indicates which symbol in the slot transmit DMRS. symbol_slot_mask dmrs_symbol_mask; diff --git a/include/srsran/phy/upper/pucch_formats_3_4_helpers.h b/include/srsran/phy/upper/pucch_formats3_4_helpers.h similarity index 99% rename from include/srsran/phy/upper/pucch_formats_3_4_helpers.h rename to include/srsran/phy/upper/pucch_formats3_4_helpers.h index 4ae41206e2..dd5a045824 100644 --- a/include/srsran/phy/upper/pucch_formats_3_4_helpers.h +++ b/include/srsran/phy/upper/pucch_formats3_4_helpers.h @@ -29,7 +29,7 @@ namespace srsran { /// set to \c false otherwise. /// \param[in] additional_dmrs Whether \e additionalDMRS parameter is set for the PUCCH resource. /// \returns The symbol mask for symbols containing DM-RS for that configuration, as per TS38.211 Table 6.4.1.3.3.2-1. -inline symbol_slot_mask get_pucch_formats_3_4_dmrs_symbol_mask( +inline symbol_slot_mask get_pucch_formats3_4_dmrs_symbol_mask( bounded_integer nof_symbols, bool frequency_hopping, bool additional_dmrs) diff --git a/include/srsran/phy/upper/pucch_helper.h b/include/srsran/phy/upper/pucch_helper.h index 7291b38fcb..d3f3c177d5 100644 --- a/include/srsran/phy/upper/pucch_helper.h +++ b/include/srsran/phy/upper/pucch_helper.h @@ -34,7 +34,10 @@ class pucch_helper } /// Computes the NR-PUCCH group sequence (TS 38.211 clause 6.3.2.2.1 Group and sequence hopping). - void compute_group_sequence(pucch_group_hopping group_hopping, unsigned n_id, unsigned& u, unsigned& v) + /// \param[in] group_hopping Group hopping configuration. + /// \param[in] n_id Scrambling identifier. + /// \return A pair of sequence group u and sequence number v. + static std::pair compute_group_sequence(pucch_group_hopping group_hopping, unsigned n_id) { unsigned f_gh = 0; unsigned f_ss = 0; @@ -45,14 +48,13 @@ class pucch_helper break; case pucch_group_hopping::ENABLE: srsran_terminate("Group hopping is not implemented"); - return; case pucch_group_hopping::DISABLE: srsran_terminate("Hopping is not implemented"); - return; } - u = (f_gh + f_ss) % low_papr_sequence_collection::NOF_GROUPS; - v = 0; + unsigned u = (f_gh + f_ss) % low_papr_sequence_collection::NOF_GROUPS; + unsigned v = 0; + return {u, v}; } /// \brief Computes the NR alpha index (1-NRE) (TS 38.211 clause 6.3.2.2.2 Cyclic shift hopping) diff --git a/include/srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h b/include/srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h index 6de2642612..6508e6ddea 100644 --- a/include/srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h +++ b/include/srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h @@ -47,13 +47,13 @@ class dmrs_pucch_estimator /// Higher layer parameter \e hoppingID if configured (Cell-specific scrambling ID for group hopping and sequence /// hopping), otherwise the physical cell identifier. unsigned n_id; - /// Port indexes the PUCCH transmission is mapped onto. + /// Port indices the PUCCH transmission is mapped onto. static_vector ports; }; /// Collects specific PUCCH Format 1 parameters. struct format1_configuration : common_configuration { - /// Initial cyclic shift, used by Formats 0 and 1 as defined in TS38.211 Section 6.3.2.2.2. + /// Initial cyclic shift, as defined in TS38.211 Section 6.3.2.2.2. unsigned initial_cyclic_shift; /// Orthogonal Cover Code Index. unsigned time_domain_occ; @@ -61,7 +61,7 @@ class dmrs_pucch_estimator /// Collects specific PUCCH Format 2 parameters. struct format2_configuration : common_configuration { - /// Number of PRBs, applicable for Formats 2 and 3 (see PUCCH-Resource IE in TS38.331). + /// Number of PRBs, see PUCCH-Resource IE in TS38.331. unsigned nof_prb; /// \brief DM-RS scrambling identity, defined in TS38.211 Section 6.4.1.3.2.1. /// @@ -75,7 +75,6 @@ class dmrs_pucch_estimator /// Number of PRBs. unsigned nof_prb; /// \brief Additional DM-RS flag (true if enabled), indicating two DM-RS symbols per hop. - /// \remark Applicable to PUCCH Formats 3 and 4. /// \remark See PUCCH-Format-Config IE in TS38.331. bool additional_dmrs; }; @@ -83,7 +82,6 @@ class dmrs_pucch_estimator /// Collects specific PUCCH Format 4 parameters. struct format4_configuration : common_configuration { /// \brief Additional DM-RS flag (true if enabled), indicating two DM-RS symbols per hop. - /// \remark Applicable to PUCCH Formats 3 and 4. /// \remark See PUCCH-Format-Config IE in TS38.331. bool additional_dmrs; /// Orthogonal Cover Code Index. diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.cpp b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.cpp index 9a80b57696..2d15f45dab 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.cpp +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.cpp @@ -14,7 +14,7 @@ #include "pucch_demodulator_format3.h" #include "srsran/phy/support/mask_types.h" #include "srsran/phy/support/resource_grid_reader.h" -#include "srsran/phy/upper/pucch_formats_3_4_helpers.h" +#include "srsran/phy/upper/pucch_formats3_4_helpers.h" using namespace srsran; @@ -27,7 +27,7 @@ void pucch_demodulator_format3::demodulate(span modulation_scheme mod_scheme = config.pi2_bpsk ? modulation_scheme::PI_2_BPSK : modulation_scheme::QPSK; // Get a boolean mask of the OFDM symbols carrying DM-RS. - symbol_slot_mask dmrs_symb_mask = get_pucch_formats_3_4_dmrs_symbol_mask( + symbol_slot_mask dmrs_symb_mask = get_pucch_formats3_4_dmrs_symbol_mask( config.nof_symbols, config.second_hop_prb.has_value(), config.additional_dmrs); // Number of REs per OFDM symbol. diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp index 5094ebd538..5b0e241c8c 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp @@ -14,7 +14,7 @@ #include "pucch_demodulator_format4.h" #include "srsran/phy/support/mask_types.h" #include "srsran/phy/support/resource_grid_reader.h" -#include "srsran/phy/upper/pucch_formats_3_4_helpers.h" +#include "srsran/phy/upper/pucch_formats3_4_helpers.h" #include "srsran/phy/upper/pucch_orthogonal_sequence.h" #include "srsran/srsvec/sc_prod.h" @@ -29,7 +29,7 @@ void pucch_demodulator_format4::demodulate(span modulation_scheme mod_scheme = config.pi2_bpsk ? modulation_scheme::PI_2_BPSK : modulation_scheme::QPSK; // Get a boolean mask of the OFDM symbols carrying DM-RS. - symbol_slot_mask dmrs_symb_mask = get_pucch_formats_3_4_dmrs_symbol_mask( + symbol_slot_mask dmrs_symb_mask = get_pucch_formats3_4_dmrs_symbol_mask( config.nof_symbols, config.second_hop_prb.has_value(), config.additional_dmrs); // Number of REs per OFDM symbol. PUCCH Format 4 only gets a PRB. diff --git a/lib/phy/upper/channel_processors/pucch/pucch_detector_format0.cpp b/lib/phy/upper/channel_processors/pucch/pucch_detector_format0.cpp index 10aa68bc4c..1e36b9d897 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_detector_format0.cpp +++ b/lib/phy/upper/channel_processors/pucch/pucch_detector_format0.cpp @@ -168,10 +168,10 @@ pucch_detector_format0::detect(const srsran::resource_grid_reader& grid float sum_noise_var = 0.0F; for (unsigned i_symbol = 0; i_symbol != nof_symbols; ++i_symbol) { - // Calculate group sequence. + // Compute group sequence. unsigned u; unsigned v; - helper.compute_group_sequence(pucch_group_hopping::NEITHER, config.n_id, u, v); + std::tie(u, v) = helper.compute_group_sequence(pucch_group_hopping::NEITHER, config.n_id); // Calculate cyclic shift. unsigned alpha = helper.get_alpha_index(config.slot, diff --git a/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.cpp b/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.cpp index 29b21ef502..2cdfeeadc7 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.cpp +++ b/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.cpp @@ -66,14 +66,14 @@ pucch_processor_result pucch_processor_impl::process(const resource_grid_reader& // Prepare channel estimation. dmrs_pucch_estimator::format1_configuration estimator_config; - estimator_config.slot = config.slot; - estimator_config.cp = config.cp; - estimator_config.start_symbol_index = config.start_symbol_index; - estimator_config.nof_symbols = config.nof_symbols; - estimator_config.starting_prb = config.starting_prb + config.bwp_start_rb; - estimator_config.second_hop_prb = config.second_hop_prb.has_value() - ? std::optional{config.second_hop_prb.value() + config.bwp_start_rb} - : std::nullopt; + estimator_config.slot = config.slot; + estimator_config.cp = config.cp; + estimator_config.start_symbol_index = config.start_symbol_index; + estimator_config.nof_symbols = config.nof_symbols; + estimator_config.starting_prb = config.starting_prb + config.bwp_start_rb; + estimator_config.second_hop_prb = transform_optional( + config.second_hop_prb, + [bwp_start_rb = config.bwp_start_rb](unsigned second_hop_prb) { return second_hop_prb + bwp_start_rb; }), estimator_config.initial_cyclic_shift = config.initial_cyclic_shift; estimator_config.time_domain_occ = config.time_domain_occ; estimator_config.n_id = config.n_id; @@ -153,12 +153,12 @@ pucch_processor_result pucch_processor_impl::process(const resource_grid_reader& estimator_config.start_symbol_index = config.start_symbol_index; estimator_config.nof_symbols = config.nof_symbols; estimator_config.starting_prb = config.bwp_start_rb + config.starting_prb; - estimator_config.second_hop_prb = config.second_hop_prb.has_value() - ? std::optional{config.second_hop_prb.value() + config.bwp_start_rb} - : std::nullopt; - estimator_config.nof_prb = config.nof_prb; - estimator_config.n_id = config.n_id; - estimator_config.n_id_0 = config.n_id_0; + estimator_config.second_hop_prb = transform_optional( + config.second_hop_prb, + [bwp_start_rb = config.bwp_start_rb](unsigned second_hop_prb) { return second_hop_prb + bwp_start_rb; }), + estimator_config.nof_prb = config.nof_prb; + estimator_config.n_id = config.n_id; + estimator_config.n_id_0 = config.n_id_0; estimator_config.ports.assign(config.ports.begin(), config.ports.end()); // Prepare channel estimate. diff --git a/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.h b/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.h index 9c16e66828..bf5372b99c 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.h +++ b/lib/phy/upper/channel_processors/pucch/pucch_processor_impl.h @@ -95,8 +95,7 @@ class pucch_processor_impl : public pucch_processor detector(std::move(detector_)), demodulator(std::move(demodulator_)), decoder(std::move(decoder_)), - estimates(estimates_dimensions), - max_sizes(estimates_dimensions) + estimates(estimates_dimensions) { srsran_assert(channel_estimator, "Invalid channel estimator."); srsran_assert(detector, "Invalid detector."); @@ -117,8 +116,6 @@ class pucch_processor_impl : public pucch_processor std::unique_ptr decoder; /// Temporal channel estimates. channel_estimate estimates; - /// Maximum RB, symbol and channel sizes handled by the processor. - channel_estimate::channel_estimate_dimensions max_sizes; /// Temporal LLR storage. std::array temp_llr; }; diff --git a/lib/phy/upper/signal_processors/CMakeLists.txt b/lib/phy/upper/signal_processors/CMakeLists.txt index 1a211ab7e4..737c2f090f 100644 --- a/lib/phy/upper/signal_processors/CMakeLists.txt +++ b/lib/phy/upper/signal_processors/CMakeLists.txt @@ -11,7 +11,7 @@ set(SOURCES ptrs/ptrs_pdsch_generator_factory.cpp pucch/dmrs_pucch_estimator_format1.cpp pucch/dmrs_pucch_estimator_format2.cpp - pucch/dmrs_pucch_estimator_formats_3_4.cpp + pucch/dmrs_pucch_estimator_formats3_4.cpp srs/srs_estimator_factory.cpp srs/srs_estimator_generic_impl.cpp srs/srs_validator_generic_impl.cpp diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format1.cpp b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format1.cpp index 68803b075b..f5ebbaa78c 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format1.cpp +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format1.cpp @@ -163,16 +163,18 @@ void dmrs_pucch_estimator_format1::estimate(channel_estimate& // Resize DM-RS symbol buffer. temp_symbols.resize(dims); - unsigned u, v; // Compute group sequence. - helper.compute_group_sequence(config.group_hopping, config.n_id, u, v); + unsigned u; + unsigned v; + std::tie(u, v) = helper.compute_group_sequence(config.group_hopping, config.n_id); // Index to write into the DM-RS buffer. unsigned i_dmrs_symb = 0; // Generate DM-RS sequences for even-numbered symbols within the PUCCH allocation, as per TS38.211 // Section 6.4.1.3.1. - for (unsigned i_hop = 0, i_symb = config.start_symbol_index; i_hop < (config.second_hop_prb.has_value() ? 2 : 1); + for (unsigned i_hop = 0, i_symb = config.start_symbol_index, last_hop = (config.second_hop_prb.has_value() ? 2 : 1); + i_hop != last_hop; ++i_hop) { // Get number of symbols carrying DM-RS in the current hop. unsigned nof_dmrs_symb_hop = dmrs_pucch_symbols(config, i_hop); @@ -198,9 +200,9 @@ void dmrs_pucch_estimator_format1::estimate(channel_estimate& est_cfg.cp = config.cp; est_cfg.first_symbol = config.start_symbol_index; est_cfg.nof_symbols = config.nof_symbols; - est_cfg.dmrs_pattern = {generate_dmrs_pattern(config)}; - est_cfg.rx_ports = config.ports; - est_cfg.scaling = 1.0F; + est_cfg.dmrs_pattern.assign(1, generate_dmrs_pattern(config)); + est_cfg.rx_ports = config.ports; + est_cfg.scaling = 1.0F; // Perform estimation for each receive port. for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format2.cpp b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format2.cpp index 0850e637f2..c7ae12c5ab 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format2.cpp +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_format2.cpp @@ -108,9 +108,9 @@ void dmrs_pucch_estimator_format2::estimate(channel_estimate& est_cfg.cp = config.cp; est_cfg.first_symbol = config.start_symbol_index; est_cfg.nof_symbols = config.nof_symbols; - est_cfg.dmrs_pattern = {generate_dmrs_pattern(config)}; - est_cfg.rx_ports = config.ports; - est_cfg.scaling = 1.0F; + est_cfg.dmrs_pattern.assign(1, generate_dmrs_pattern(config)); + est_cfg.rx_ports = config.ports; + est_cfg.scaling = 1.0F; // Perform estimation for each receive port. for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats_3_4.cpp b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats3_4.cpp similarity index 65% rename from lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats_3_4.cpp rename to lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats3_4.cpp index 93b5754f7c..60477fd170 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats_3_4.cpp +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats3_4.cpp @@ -8,17 +8,17 @@ * */ -#include "dmrs_pucch_estimator_formats_3_4.h" -#include "srsran/phy/upper/pucch_formats_3_4_helpers.h" +#include "dmrs_pucch_estimator_formats3_4.h" +#include "srsran/phy/upper/pucch_formats3_4_helpers.h" #include "srsran/ran/pucch/pucch_constants.h" using namespace srsran; -void dmrs_pucch_estimator_formats_3_4::generate_sequence(span sequence, - const estimate_config& config, - unsigned u, - unsigned v, - unsigned symbol) +void dmrs_pucch_estimator_formats3_4::generate_sequence(span sequence, + const estimate_config& config, + unsigned u, + unsigned v, + unsigned symbol) { unsigned m_0 = 0; // m_0 for PUCCH Format 4 is selected according to TS38.211 Table 6.4.1.3.3.1-1. @@ -46,8 +46,8 @@ void dmrs_pucch_estimator_formats_3_4::generate_sequence(span low_papr_generator->generate(sequence, u, v, alpha_idx, NRE); } -dmrs_pucch_estimator_formats_3_4::layer_dmrs_pattern -dmrs_pucch_estimator_formats_3_4::generate_dmrs_pattern(const estimate_config& config) +dmrs_pucch_estimator_formats3_4::layer_dmrs_pattern +dmrs_pucch_estimator_formats3_4::generate_dmrs_pattern(const estimate_config& config) { layer_dmrs_pattern mask; @@ -68,7 +68,7 @@ dmrs_pucch_estimator_formats_3_4::generate_dmrs_pattern(const estimate_config& c mask.hopping_symbol_index = config.start_symbol_index + (config.nof_symbols / 2); } - symbol_slot_mask dmrs_symb_mask = get_pucch_formats_3_4_dmrs_symbol_mask( + symbol_slot_mask dmrs_symb_mask = get_pucch_formats3_4_dmrs_symbol_mask( config.nof_symbols, config.second_hop_prb.has_value(), config.additional_dmrs); mask.symbols.resize(get_nsymb_per_slot(config.cp)); @@ -79,11 +79,11 @@ dmrs_pucch_estimator_formats_3_4::generate_dmrs_pattern(const estimate_config& c return mask; } -void dmrs_pucch_estimator_formats_3_4::estimate(channel_estimate& estimate, - const resource_grid_reader& grid, - const estimate_config& config) +void dmrs_pucch_estimator_formats3_4::estimate(channel_estimate& estimate, + const resource_grid_reader& grid, + const estimate_config& config) { - symbol_slot_mask dmrs_symb_mask = get_pucch_formats_3_4_dmrs_symbol_mask( + symbol_slot_mask dmrs_symb_mask = get_pucch_formats3_4_dmrs_symbol_mask( config.nof_symbols, config.second_hop_prb.has_value(), config.additional_dmrs); // Prepare DM-RS symbol buffer dimensions. @@ -95,14 +95,15 @@ void dmrs_pucch_estimator_formats_3_4::estimate(channel_estimate& esti // Resize DM-RS symbol buffer. temp_symbols.resize(dims); - unsigned u, v; - helper.compute_group_sequence(config.group_hopping, config.n_id, u, v); - - unsigned i_symb_start = config.start_symbol_index; - unsigned i_symb_end = config.start_symbol_index + config.nof_symbols; + // Compute group sequence. + unsigned u; + unsigned v; + std::tie(u, v) = helper.compute_group_sequence(config.group_hopping, config.n_id); unsigned i_dmrs_symb = 0; - for (unsigned i_symb = i_symb_start; i_symb != i_symb_end; ++i_symb) { + for (unsigned i_symb = config.start_symbol_index, i_symb_end = config.start_symbol_index + config.nof_symbols; + i_symb != i_symb_end; + ++i_symb) { // For each symbol carrying DM-RS. if (!dmrs_symb_mask.test(i_symb - config.start_symbol_index)) { continue; @@ -118,21 +119,19 @@ void dmrs_pucch_estimator_formats_3_4::estimate(channel_estimate& esti est_cfg.cp = config.cp; est_cfg.first_symbol = config.start_symbol_index; est_cfg.nof_symbols = config.nof_symbols; - est_cfg.dmrs_pattern = {generate_dmrs_pattern(config)}; - est_cfg.rx_ports = config.ports; - est_cfg.scaling = 1.0F; - - unsigned nof_rx_ports = config.ports.size(); + est_cfg.dmrs_pattern.assign(1, generate_dmrs_pattern(config)); + est_cfg.rx_ports = config.ports; + est_cfg.scaling = 1.0F; // Perform estimation for each receive port. - for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { + for (unsigned i_port = 0, nof_rx_ports = config.ports.size(); i_port != nof_rx_ports; ++i_port) { ch_estimator->compute(estimate, grid, i_port, temp_symbols, est_cfg); } } -void dmrs_pucch_estimator_formats_3_4::estimate(channel_estimate& ch_estimate, - const resource_grid_reader& grid, - const dmrs_pucch_estimator::format3_configuration& config) +void dmrs_pucch_estimator_formats3_4::estimate(channel_estimate& ch_estimate, + const resource_grid_reader& grid, + const dmrs_pucch_estimator::format3_configuration& config) { estimate_config est_cfg = { .slot = config.slot, @@ -152,9 +151,9 @@ void dmrs_pucch_estimator_formats_3_4::estimate(channel_estimate& estimate(ch_estimate, grid, est_cfg); } -void dmrs_pucch_estimator_formats_3_4::estimate(channel_estimate& ch_estimate, - const resource_grid_reader& grid, - const dmrs_pucch_estimator::format4_configuration& config) +void dmrs_pucch_estimator_formats3_4::estimate(channel_estimate& ch_estimate, + const resource_grid_reader& grid, + const dmrs_pucch_estimator::format4_configuration& config) { estimate_config est_cfg = { .slot = config.slot, diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats_3_4.h b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats3_4.h similarity index 80% rename from lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats_3_4.h rename to lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats3_4.h index ac690b4656..2469f7f9ac 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats_3_4.h +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_formats3_4.h @@ -19,14 +19,14 @@ namespace srsran { /// Generic implementation of a DM-RS channel estimator for PUCCH Formats 3 and 4. -class dmrs_pucch_estimator_formats_3_4 +class dmrs_pucch_estimator_formats3_4 { public: using layer_dmrs_pattern = port_channel_estimator::layer_dmrs_pattern; - dmrs_pucch_estimator_formats_3_4(std::unique_ptr prg_, - std::unique_ptr low_papr_generator_, - std::unique_ptr ch_est_) : + dmrs_pucch_estimator_formats3_4(std::unique_ptr prg_, + std::unique_ptr low_papr_generator_, + std::unique_ptr ch_est_) : helper(std::move(prg_)), low_papr_generator(std::move(low_papr_generator_)), ch_estimator(std::move(ch_est_)) { srsran_assert(low_papr_generator, "Invalid sequence generator."); @@ -44,6 +44,7 @@ class dmrs_pucch_estimator_formats_3_4 const dmrs_pucch_estimator::format4_configuration& config); private: + /// PUCCH helper functions. pucch_helper helper; /// PUCCH Formats 3 and 4 implementation expects pre-generated sequence collection on instantiation. @@ -56,29 +57,29 @@ class dmrs_pucch_estimator_formats_3_4 /// Common configuration parameters for PUCCH Formats 3 and 4. struct estimate_config { - // Slot timing and numerology. + /// Slot timing and numerology. slot_point slot; - // Cyclic Prefix. + /// Cyclic Prefix. cyclic_prefix cp; - // Group and sequence hopping configuration. + /// Group and sequence hopping configuration. pucch_group_hopping group_hopping; - // Parameter \f$n_{ID}\f$ in TS38.211 Section 6.3.2.2.2. + /// Parameter \f$n_{ID}\f$ in TS38.211 Section 6.3.2.2.2. unsigned n_id; - // Number of PRBs. + /// Number of PRBs. unsigned nof_prb; - // Number of OFDM symbols assigned to resource. + /// Number of OFDM symbols assigned to resource. unsigned nof_symbols; - // Start PRB index. + /// Start PRB index. unsigned starting_prb; - // Index of first PRB of the second hop if intra-slot frequency hopping is enabled, empty otherwise. + /// Index of first PRB of the second hop if intra-slot frequency hopping is enabled, empty otherwise. std::optional second_hop_prb; - // Start symbol index. + /// Start symbol index. unsigned start_symbol_index; - // Additional DM-RS flag. + /// Additional DM-RS flag. bool additional_dmrs; - // Orthogonal Cover Code. + /// Orthogonal Cover Code. unsigned occ_index; - // Port indexes the PUCCH transmission is mapped onto. + /// Port indices the PUCCH transmission is mapped onto. const static_vector& ports; }; diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_impl.h b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_impl.h index 0383741785..c30d617b4a 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_impl.h +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_estimator_impl.h @@ -15,7 +15,7 @@ #include "dmrs_pucch_estimator_format1.h" #include "dmrs_pucch_estimator_format2.h" -#include "dmrs_pucch_estimator_formats_3_4.h" +#include "dmrs_pucch_estimator_formats3_4.h" #include "srsran/phy/upper/signal_processors/dmrs_pucch_estimator.h" namespace srsran { @@ -27,17 +27,17 @@ class dmrs_pucch_estimator_impl : public dmrs_pucch_estimator /// Constructor: sets up internal components and acquires their ownership. /// \param[in] estimator_format1_ PUCCH Format 1 DM-RS estimator. /// \param[in] estimator_format2_ PUCCH Format 1 DM-RS estimator. - /// \param[in] estimator_formats_3_4_ PUCCH Format 3 and Format 4 DM-RS estimator. - dmrs_pucch_estimator_impl(std::unique_ptr estimator_format1_, - std::unique_ptr estimator_format2_, - std::unique_ptr estimator_formats_3_4_) : + /// \param[in] estimator_formats3_4_ PUCCH Format 3 and Format 4 DM-RS estimator. + dmrs_pucch_estimator_impl(std::unique_ptr estimator_format1_, + std::unique_ptr estimator_format2_, + std::unique_ptr estimator_formats3_4_) : estimator_format1(std::move(estimator_format1_)), estimator_format2(std::move(estimator_format2_)), - estimator_formats_3_4(std::move(estimator_formats_3_4_)) + estimator_formats3_4(std::move(estimator_formats3_4_)) { srsran_assert(estimator_format1, "Invalid pointer to dmrs_pucch_estimator_format1 object."); srsran_assert(estimator_format2, "Invalid pointer to dmrs_pucch_estimator_format2 object."); - srsran_assert(estimator_formats_3_4, "Invalid pointer to dmrs_pucch_estimator_formats_3_4 object."); + srsran_assert(estimator_formats3_4, "Invalid pointer to dmrs_pucch_estimator_formats3_4 object."); } // See interface for the documentation. @@ -58,14 +58,14 @@ class dmrs_pucch_estimator_impl : public dmrs_pucch_estimator void estimate(channel_estimate& estimate, const resource_grid_reader& grid, const format3_configuration& config) override { - estimator_formats_3_4->estimate(estimate, grid, config); + estimator_formats3_4->estimate(estimate, grid, config); } // See interface for the documentation. void estimate(channel_estimate& estimate, const resource_grid_reader& grid, const format4_configuration& config) override { - estimator_formats_3_4->estimate(estimate, grid, config); + estimator_formats3_4->estimate(estimate, grid, config); } private: @@ -74,7 +74,7 @@ class dmrs_pucch_estimator_impl : public dmrs_pucch_estimator /// PUCCH DM-RS estimator Format 1 component. std::unique_ptr estimator_format2; /// PUCCH DM-RS estimator Format 3 and Format 4 component. - std::unique_ptr estimator_formats_3_4; + std::unique_ptr estimator_formats3_4; }; } // namespace srsran diff --git a/lib/phy/upper/signal_processors/signal_processor_factories.cpp b/lib/phy/upper/signal_processors/signal_processor_factories.cpp index 94f5b1949e..8d229bb39e 100644 --- a/lib/phy/upper/signal_processors/signal_processor_factories.cpp +++ b/lib/phy/upper/signal_processors/signal_processor_factories.cpp @@ -19,7 +19,7 @@ #include "pss_processor_impl.h" #include "pucch/dmrs_pucch_estimator_format1.h" #include "pucch/dmrs_pucch_estimator_format2.h" -#include "pucch/dmrs_pucch_estimator_formats_3_4.h" +#include "pucch/dmrs_pucch_estimator_formats3_4.h" #include "pucch/dmrs_pucch_estimator_impl.h" #include "sss_processor_impl.h" #include "srsran/phy/support/support_factories.h" @@ -126,15 +126,15 @@ class dmrs_pucch_estimator_sw_factory : public dmrs_pucch_estimator_factory std::unique_ptr estimator_format2 = std::make_unique( prg_factory->create(), ch_estimator_factory->create(port_channel_estimator_fd_smoothing_strategy::filter)); - std::unique_ptr estimator_formats_3_4 = - std::make_unique( + std::unique_ptr estimator_formats3_4 = + std::make_unique( prg_factory->create(), lpg_factory->create(), ch_estimator_factory->create(port_channel_estimator_fd_smoothing_strategy::mean, /*compensate_cfo =*/false)); return std::make_unique( - std::move(estimator_format1), std::move(estimator_format2), std::move(estimator_formats_3_4)); + std::move(estimator_format1), std::move(estimator_format2), std::move(estimator_formats3_4)); } private: diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format3_test.cpp b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format3_test.cpp index 4bd9c06317..2ce376de21 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format3_test.cpp +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format3_test.cpp @@ -15,7 +15,7 @@ #include "srsran/phy/upper/channel_processors/pucch/factories.h" #include "srsran/phy/upper/channel_processors/pucch/pucch_demodulator.h" #include "srsran/phy/upper/equalization/equalization_factories.h" -#include "srsran/phy/upper/pucch_formats_3_4_helpers.h" +#include "srsran/phy/upper/pucch_formats3_4_helpers.h" #include "srsran/ran/pucch/pucch_constants.h" #include "srsran/srsvec/conversion.h" #include "srsran/support/format/fmt_optional.h" @@ -128,7 +128,7 @@ class PucchDemodulatorFixture : public ::testing::TestWithParam& get_format1_entries() const { return format1_entries; } - const std::vector& get_format2_entries() const { return format2_entries; } - const std::vector& get_format3_entries() const { return format3_entries; } - const std::vector& get_format4_entries() const { return format4_entries; } + span get_format1_entries() const { return format1_entries; } + span get_format2_entries() const { return format2_entries; } + span get_format3_entries() const { return format3_entries; } + span get_format4_entries() const { return format4_entries; } void clear() { From 4c4bdf36b4fe8d2cd0007bf53ab452cc892ca872 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 11 Nov 2024 16:51:04 +0100 Subject: [PATCH 14/26] phy: fix SIMD --- include/srsran/srsvec/simd.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/srsran/srsvec/simd.h b/include/srsran/srsvec/simd.h index b98811f78d..276433c966 100644 --- a/include/srsran/srsvec/simd.h +++ b/include/srsran/srsvec/simd.h @@ -1519,6 +1519,25 @@ inline simd_i_t srsran_simd_i_and(simd_i_t a, simd_i_t b) #endif /* __AVX512F__ */ } +inline simd_sel_t srsran_simd_sel_set_ones() +{ +#ifdef __AVX512F__ + return ~static_cast(0); +#else /* __AVX512F__ */ +#ifdef __AVX2__ + return _mm256_castsi256_ps(_mm256_set1_epi32(0xffffffff)); +#else +#ifdef __SSE4_1__ + return _mm_castsi256_ps(_mm_set1_epi32(0xffffffff)); +#else +#ifdef __ARM_NEON + return vdupq_n_u32(0xffffffff); +#endif /* __ARM_NEON */ +#endif /* __SSE4_1__ */ +#endif /* __AVX2__ */ +#endif /* __AVX512F__ */ +} + inline simd_sel_t srsran_simd_sel_and(simd_sel_t a, simd_sel_t b) { #ifdef __AVX512F__ From ecbe23320edc524afbf0a2140fe7f51f5d946300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Mon, 11 Nov 2024 15:19:48 +0100 Subject: [PATCH 15/26] ci-shared: remove old unused functions --- .gitlab/ci-shared/build.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.gitlab/ci-shared/build.yml b/.gitlab/ci-shared/build.yml index 0cd2218e0c..4cebfadf61 100644 --- a/.gitlab/ci-shared/build.yml +++ b/.gitlab/ci-shared/build.yml @@ -117,14 +117,6 @@ variables: builder.sh -m "-j${KUBERNETES_CPU_REQUEST} ${target}" ${BUILD_CMD} "$@" ${SRSRANDIR} { set +x; } 2>/dev/null } - - | - build_plugin() { - target="$1" - shift - set -x - builder.sh -m "-j${KUBERNETES_CPU_REQUEST} ${target}" ${BUILD_CMD} "$@" ${CI_PROJECT_DIR} - { set +x; } 2>/dev/null - } - | launch_tests_srsran() { cd ${SRSRANDIR}/build @@ -133,11 +125,3 @@ variables: ctest -j${KUBERNETES_CPU_REQUEST} --schedule-random --output-on-failure --output-junit xunit.xml "$@" { set +x; } 2>/dev/null } - - | - launch_tests_plugin() { - cd ${CI_PROJECT_DIR}/build - echo "Using LD_LIBRARY_PATH=$LD_LIBRARY_PATH" - set -x - ctest -j${KUBERNETES_CPU_REQUEST} --schedule-random --output-on-failure --output-junit xunit.xml "$@" - { set +x; } 2>/dev/null - } From 5eb9f902e40a5c752fcbcae76006c34f986f1d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Mon, 11 Nov 2024 15:20:04 +0100 Subject: [PATCH 16/26] ci,e2e: update viavi tests parameters --- .gitlab/ci/e2e/.env | 2 +- tests/e2e/tests/viavi/test_declaration.yml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 03bbe9f76e..45c8845504 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.54.12 +RETINA_VERSION=0.54.13 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 diff --git a/tests/e2e/tests/viavi/test_declaration.yml b/tests/e2e/tests/viavi/test_declaration.yml index 5131ebb296..d36a7a48bc 100644 --- a/tests/e2e/tests/viavi/test_declaration.yml +++ b/tests/e2e/tests/viavi/test_declaration.yml @@ -20,7 +20,7 @@ # warning_as_errors: treat warnings as errors campaign_filename: &campaign_filename "C:\\ci\\CI 4x4 ORAN-FH-complete.xml" -gnb_extra_commands: &gnb_extra_commands "log --metrics_level=info metrics --rlc_report_period=1000 ru_ofh --ta4_max=700 --ta4_min=10" +gnb_extra_commands: &gnb_extra_commands "log --metrics_level=info metrics --rlc_report_period=1000" test_timeout: &test_timeout 2400 tests: @@ -139,7 +139,7 @@ tests: - campaign_filename: *campaign_filename test_name: "32UE ideal UDP attach-detach with traffic" test_timeout: *test_timeout - gnb_extra_commands: "log --ngap_level=debug --metrics_level=info metrics --rlc_report_period=1000" + gnb_extra_commands: *gnb_extra_commands id: "32UE ideal UDP attach-detach with traffic" max_pdschs_per_slot: 1 max_puschs_per_slot: 4 @@ -153,7 +153,7 @@ tests: - campaign_filename: *campaign_filename test_name: "32UE ideal UDP attach-detach with traffic High brate" test_timeout: *test_timeout - gnb_extra_commands: "log --ngap_level=debug --metrics_level=info metrics --rlc_report_period=1000" + gnb_extra_commands: *gnb_extra_commands id: "32UE ideal UDP attach-detach with traffic tdd DDDSU" max_pdschs_per_slot: 1 max_puschs_per_slot: 4 @@ -168,7 +168,7 @@ tests: - campaign_filename: *campaign_filename test_name: "32UE ideal UDP attach-detach with traffic High brate" test_timeout: *test_timeout - gnb_extra_commands: "log --ngap_level=debug --metrics_level=info metrics --rlc_report_period=1000" + gnb_extra_commands: *gnb_extra_commands id: "32UE ideal UDP attach-detach with traffic tdd UL Heavy 7u2d" max_pdschs_per_slot: 1 max_puschs_per_slot: 4 @@ -183,7 +183,7 @@ tests: - campaign_filename: *campaign_filename test_name: "32UE ideal UDP attach-detach with traffic High brate" test_timeout: *test_timeout - gnb_extra_commands: "log --ngap_level=debug --metrics_level=info metrics --rlc_report_period=1000" + gnb_extra_commands: *gnb_extra_commands id: "32UE ideal UDP attach-detach with traffic tdd UL Heavy 6u3d" max_pdschs_per_slot: 1 max_puschs_per_slot: 4 From fd67133bbc6a4f9ae34514179cbf9827a16af394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Mon, 11 Nov 2024 17:02:57 +0100 Subject: [PATCH 17/26] ci,e2e: print dl and ul KOs in two different rows in criteria table --- tests/e2e/tests/steps/kpis.py | 6 ++++-- tests/e2e/tests/viavi.py | 23 ++++++++++++++++------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/tests/e2e/tests/steps/kpis.py b/tests/e2e/tests/steps/kpis.py index 60f35ba5e9..a8387dd070 100644 --- a/tests/e2e/tests/steps/kpis.py +++ b/tests/e2e/tests/steps/kpis.py @@ -35,7 +35,8 @@ class KPIs: dl_brate_max: float = 0 ul_bler_aggregate: float = 0 dl_bler_aggregate: float = 0 - nof_ko_aggregate: int = 0 + nof_ko_ul: int = 0 + nof_ko_dl: int = 0 nof_attach_failures: int = 0 nof_reestablishments: int = 0 nof_handovers: int = 0 @@ -65,7 +66,8 @@ def get_kpis( kpis.dl_brate_min = gnb_metrics.total.dl_bitrate_min kpis.dl_brate_max = gnb_metrics.total.dl_bitrate_max - kpis.nof_ko_aggregate = gnb_metrics.total.dl_nof_ko + gnb_metrics.total.ul_nof_ko + kpis.nof_ko_dl = gnb_metrics.total.dl_nof_ko + kpis.nof_ko_ul = gnb_metrics.total.ul_nof_ko total_ul_ko_ok = gnb_metrics.total.ul_nof_ok + gnb_metrics.total.ul_nof_ko total_dl_ko_ok = gnb_metrics.total.dl_nof_ok + gnb_metrics.total.dl_nof_ko diff --git a/tests/e2e/tests/viavi.py b/tests/e2e/tests/viavi.py index ab36f17809..3345790cec 100644 --- a/tests/e2e/tests/viavi.py +++ b/tests/e2e/tests/viavi.py @@ -487,23 +487,31 @@ def check_metrics_criteria( ) ) - criteria_nof_ko_aggregate = check_criteria(kpis.nof_ko_aggregate, test_configuration.expected_nof_kos, operator.lt) + criteria_nof_ko_dl = check_criteria(kpis.nof_ko_dl, test_configuration.expected_nof_kos, operator.lt) criteria_result.append( _ViaviResult( - "Number of KOs & retrxs", + "DL KOs", test_configuration.expected_nof_kos, - kpis.nof_ko_aggregate, - criteria_nof_ko_aggregate, + kpis.nof_ko_dl, + criteria_nof_ko_dl, ) ) - criteria_nof_errors = check_criteria(gnb_error_count, 0, operator.eq) + criteria_nof_ko_ul = check_criteria(kpis.nof_ko_ul, test_configuration.expected_nof_kos, operator.lt) criteria_result.append( _ViaviResult( - "Number of errors" + (" & warnings" if warning_as_errors else ""), 0, gnb_error_count, criteria_nof_errors + "UL KOs", + test_configuration.expected_nof_kos, + kpis.nof_ko_ul, + criteria_nof_ko_ul, ) ) + criteria_nof_errors = check_criteria(gnb_error_count, 0, operator.eq) + criteria_result.append( + _ViaviResult("Errors" + (" & warnings" if warning_as_errors else ""), 0, gnb_error_count, criteria_nof_errors) + ) + # Check procedure table viavi_failure_manager.print_failures(_OMIT_VIAVI_FAILURE_LIST) criteria_procedure_table = viavi_failure_manager.get_number_of_failures(_OMIT_VIAVI_FAILURE_LIST) == 0 @@ -519,7 +527,8 @@ def check_metrics_criteria( is_ok = ( criteria_dl_brate_aggregate and criteria_ul_brate_aggregate - and criteria_nof_ko_aggregate + and criteria_nof_ko_dl + and criteria_nof_ko_ul and criteria_procedure_table ) From 2412eb9a7c014f02d76960107d27a2e5e187f186 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 6 Nov 2024 19:25:56 +0100 Subject: [PATCH 18/26] Initial types and functions for DRX mac: implementation of drx-config controller in the scheduler --- include/srsran/ran/drx_config.h | 40 +++++++ include/srsran/ran/prach/rach_config_common.h | 3 + .../srsran/scheduler/scheduler_configurator.h | 3 + lib/ran/CMakeLists.txt | 3 +- lib/ran/drx_config.cpp | 34 ++++++ lib/scheduler/config/ue_configuration.cpp | 13 ++- lib/scheduler/config/ue_configuration.h | 13 ++- lib/scheduler/ue_context/CMakeLists.txt | 1 + lib/scheduler/ue_context/ue.cpp | 3 +- lib/scheduler/ue_context/ue.h | 4 + .../ue_context/ue_drx_controller.cpp | 102 ++++++++++++++++++ lib/scheduler/ue_context/ue_drx_controller.h | 58 ++++++++++ 12 files changed, 268 insertions(+), 9 deletions(-) create mode 100644 include/srsran/ran/drx_config.h create mode 100644 lib/ran/drx_config.cpp create mode 100644 lib/scheduler/ue_context/ue_drx_controller.cpp create mode 100644 lib/scheduler/ue_context/ue_drx_controller.h diff --git a/include/srsran/ran/drx_config.h b/include/srsran/ran/drx_config.h new file mode 100644 index 0000000000..03c68ed056 --- /dev/null +++ b/include/srsran/ran/drx_config.h @@ -0,0 +1,40 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "srsran/adt/span.h" +#include + +namespace srsran { + +/// Configuration of a UE Discontinuous Reception (DRX) mode. +struct drx_config { + /// Period of the DRX cycle. See "drx-LongCycleStartOffset" in TS 38.331. + std::chrono::milliseconds long_cycle; + /// Start Offset of the DRX long cycle.. See "drx-LongCycleStartOffset" in TS 38.331. Values {0,...,long_cycle - 1} + std::chrono::milliseconds long_start_offset; + /// Duration at the beginning of a DRX cycle. + std::chrono::milliseconds on_duration_timer; + /// Duration of the UE inactivity timer. + std::chrono::milliseconds inactivity_timer; +}; + +namespace drx_helper { + +/// Valid drx-LongCycle values as per TS 38.331, "drx-LongCycleStartOffset". +span valid_long_cycle_values(); + +/// Valid drx-onDurationTimer values as per TS 38.331, "drx-LongCycleStartOffset". +span valid_on_duration_timer_values(); + +} // namespace drx_helper + +} // namespace srsran diff --git a/include/srsran/ran/prach/rach_config_common.h b/include/srsran/ran/prach/rach_config_common.h index ba9d6fd8a5..7220183810 100644 --- a/include/srsran/ran/prach/rach_config_common.h +++ b/include/srsran/ran/prach/rach_config_common.h @@ -13,6 +13,7 @@ #include "restricted_set_config.h" #include "srsran/adt/bounded_integer.h" #include "srsran/ran/subcarrier_spacing.h" +#include #include namespace srsran { @@ -45,6 +46,8 @@ struct rach_config_common { rach_config_generic rach_cfg_generic; /// Total number of prambles used for contention based and contention free RA. Values: (1..64). std::optional total_nof_ra_preambles; + /// Maximum time for the Contention Resolution. Values: {8, 16, 24, 32, 40, 48, 56, 64}. + std::chrono::milliseconds ra_con_res_timer{64}; /// PRACH Root Sequence Index can be of 2 types, as per \c prach-RootSequenceIndex, \c RACH-ConfigCommon, TS 38.331. /// We use \c true for l839, while \c false for l139. bool is_prach_root_seq_index_l839; diff --git a/include/srsran/scheduler/scheduler_configurator.h b/include/srsran/scheduler/scheduler_configurator.h index 97e19a558d..5d47872cc4 100644 --- a/include/srsran/scheduler/scheduler_configurator.h +++ b/include/srsran/scheduler/scheduler_configurator.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/ran/carrier_configuration.h" +#include "srsran/ran/drx_config.h" #include "srsran/ran/du_types.h" #include "srsran/ran/logical_channel/lcid.h" #include "srsran/ran/pci.h" @@ -142,6 +143,8 @@ struct sched_ue_config_request { std::optional res_alloc_cfg; /// List of QoS and slicing information for DRBs. std::vector drb_info_list; + /// DRX-Config. + std::optional drx_cfg; }; /// Request to create a new UE in scheduler. diff --git a/lib/ran/CMakeLists.txt b/lib/ran/CMakeLists.txt index f450ffdfa4..8b14217e5e 100644 --- a/lib/ran/CMakeLists.txt +++ b/lib/ran/CMakeLists.txt @@ -49,7 +49,8 @@ add_library(srsran_ran ssb_freq_position_generator.cpp ssb_gscn.cpp ssb_mapping.cpp - tdd_ul_dl_config.cpp) + tdd_ul_dl_config.cpp + drx_config.cpp) target_link_libraries(srsran_ran srslog) add_to_exported_libs(srsran_ran) diff --git a/lib/ran/drx_config.cpp b/lib/ran/drx_config.cpp new file mode 100644 index 0000000000..4b32bba363 --- /dev/null +++ b/lib/ran/drx_config.cpp @@ -0,0 +1,34 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsran/ran/drx_config.h" + +using namespace srsran; +using namespace drx_helper; + +span srsran::drx_helper::valid_long_cycle_values() +{ + using msec = std::chrono::milliseconds; + static constexpr std::array values{msec{10}, msec{20}, msec{32}, msec{40}, msec{60}, + msec{64}, msec{70}, msec{80}, msec{128}, msec{160}, + msec{256}, msec{320}, msec{512}, msec{640}, msec{1024}, + msec{1280}, msec{2048}, msec{2560}, msec{5120}, msec{10240}}; + return values; +} + +span srsran::drx_helper::valid_on_duration_timer_values() +{ + using msec = std::chrono::milliseconds; + static constexpr std::array values{msec{1}, msec{2}, msec{3}, msec{4}, msec{5}, msec{6}, + msec{8}, msec{10}, msec{20}, msec{30}, msec{40}, msec{50}, + msec{60}, msec{80}, msec{100}, msec{200}, msec{300}, msec{400}, + msec{500}, msec{600}, msec{800}, msec{1000}, msec{1200}, msec{1600}}; + return values; +} diff --git a/lib/scheduler/config/ue_configuration.cpp b/lib/scheduler/config/ue_configuration.cpp index 62ff5e244d..c57976576e 100644 --- a/lib/scheduler/config/ue_configuration.cpp +++ b/lib/scheduler/config/ue_configuration.cpp @@ -590,10 +590,12 @@ ue_cell_configuration::ue_cell_configuration(const ue_cell_configuration& other) } void ue_cell_configuration::reconfigure(const serving_cell_config& cell_cfg_ded_req, - const std::optional& meas_gaps_) + const std::optional& meas_gaps_, + const std::optional& drx_cfg_) { cell_cfg_ded = cell_cfg_ded_req; meas_gap_cfg = meas_gaps_; + drx_cfg = drx_cfg_; // Clear previous lookup tables. bwp_table = {}; @@ -787,7 +789,7 @@ ue_configuration::ue_configuration(du_ue_index_t ue_inde rnti_t crnti_, const cell_common_configuration_list& common_cells, const sched_ue_config_request& cfg_req) : - ue_index(ue_index_), crnti(crnti_) + ue_index(ue_index_), crnti(crnti_), ue_drx_cfg(cfg_req.drx_cfg) { update(common_cells, cfg_req); } @@ -837,9 +839,10 @@ void ue_configuration::update(const cell_common_configuration_list& common_cells if (not du_cells.contains(cell_index)) { // New Cell. - du_cells.emplace(cell_index, - std::make_unique( - crnti, *common_cells[cell_index], ded_cell.serv_cell_cfg, ded_cell.meas_gap_cfg, e > 1)); + du_cells.emplace( + cell_index, + std::make_unique( + crnti, *common_cells[cell_index], ded_cell.serv_cell_cfg, ded_cell.meas_gap_cfg, e > 1)); } else { // Reconfiguration of existing cell. du_cells[cell_index]->reconfigure(ded_cell.serv_cell_cfg, ded_cell.meas_gap_cfg); diff --git a/lib/scheduler/config/ue_configuration.h b/lib/scheduler/config/ue_configuration.h index a373674248..f804c398dd 100644 --- a/lib/scheduler/config/ue_configuration.h +++ b/lib/scheduler/config/ue_configuration.h @@ -102,7 +102,8 @@ class ue_cell_configuration ue_cell_configuration& operator=(ue_cell_configuration&&) = delete; void reconfigure(const serving_cell_config& cell_cfg_ded_, - const std::optional& meas_gaps = std::nullopt); + const std::optional& meas_gaps = std::nullopt, + const std::optional& drx_cfg_ = std::nullopt); void set_rrm_config(const sched_ue_resource_alloc_config& ue_res_alloc_cfg); @@ -112,7 +113,8 @@ class ue_cell_configuration /// Retrieve the parameters relative to the RRM of a UE in the scheduler. const sched_ue_resource_alloc_config& rrm_cfg() const { return ue_res_alloc_cfg; } - const serving_cell_config& cfg_dedicated() const { return cell_cfg_ded; } + const serving_cell_config& cfg_dedicated() const { return cell_cfg_ded; } + const std::optional& get_drx_cfg() const { return drx_cfg; } /// Returns whether UE dedicated configuration is considered complete or not for scheduling the UE as a non-fallback /// UE. @@ -197,6 +199,7 @@ class ue_cell_configuration /// Dedicated cell configuration. serving_cell_config cell_cfg_ded; std::optional meas_gap_cfg; + std::optional drx_cfg; bool multi_cells_configured; /// Lookup table for BWP params indexed by BWP-Id. @@ -282,6 +285,9 @@ class ue_configuration /// Get QoS information of DRBs configured for the UE. span drbs_qos_info() const { return drb_qos_list; } + /// Get DRX configuration for the UE cell group. + const std::optional& drx_cfg() const { return ue_drx_cfg; } + private: // List of configured logical channels std::vector lc_list; @@ -294,6 +300,9 @@ class ue_configuration // Mapping of UE Cell indexes to DU cell indexes. std::vector ue_cell_to_du_cell_index; + + // DRX config for the UE cell group. + std::optional ue_drx_cfg; }; } // namespace srsran diff --git a/lib/scheduler/ue_context/CMakeLists.txt b/lib/scheduler/ue_context/CMakeLists.txt index dc103dfa31..5a4f4ecbc2 100644 --- a/lib/scheduler/ue_context/CMakeLists.txt +++ b/lib/scheduler/ue_context/CMakeLists.txt @@ -12,6 +12,7 @@ set(SOURCES ta_manager.cpp ue_channel_state_manager.cpp ue_link_adaptation_controller.cpp + ue_drx_controller.cpp ue.cpp ue_cell.cpp) diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index b116067962..9e87087069 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -23,7 +23,8 @@ ue::ue(const ue_creation_command& cmd) : ue_ded_cfg(&cmd.cfg), pcell_harq_pool(cmd.pcell_harq_pool), logger(srslog::fetch_basic_logger("SCHED")), - ta_mgr(expert_cfg, cell_cfg_common.ul_cfg_common.init_ul_bwp.generic_params.scs, &dl_lc_ch_mgr) + ta_mgr(expert_cfg, cell_cfg_common.ul_cfg_common.init_ul_bwp.generic_params.scs, &dl_lc_ch_mgr), + drx(cell_cfg_common, cmd.cfg.drx_cfg(), ul_lc_ch_mgr) { // Apply configuration. handle_reconfiguration_request(ue_reconf_command{cmd.cfg}); diff --git a/lib/scheduler/ue_context/ue.h b/lib/scheduler/ue_context/ue.h index 3d30815921..1608f234b0 100644 --- a/lib/scheduler/ue_context/ue.h +++ b/lib/scheduler/ue_context/ue.h @@ -13,6 +13,7 @@ #include "dl_logical_channel_manager.h" #include "ta_manager.h" #include "ue_cell.h" +#include "ue_drx_controller.h" #include "ul_logical_channel_manager.h" #include "srsran/ran/du_types.h" #include "srsran/scheduler/mac_scheduler.h" @@ -213,6 +214,9 @@ class ue /// UE Timing Advance Manager. ta_manager ta_mgr; + + // Controller of DRX active timer. + ue_drx_controller drx; }; } // namespace srsran diff --git a/lib/scheduler/ue_context/ue_drx_controller.cpp b/lib/scheduler/ue_context/ue_drx_controller.cpp new file mode 100644 index 0000000000..0eb66a5772 --- /dev/null +++ b/lib/scheduler/ue_context/ue_drx_controller.cpp @@ -0,0 +1,102 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "ue_drx_controller.h" +#include "../config/ue_configuration.h" +#include "ul_logical_channel_manager.h" + +using namespace srsran; + +ue_drx_controller::ue_drx_controller(const cell_configuration& cell_cfg_common_, + const std::optional& drx_cfg_, + const ul_logical_channel_manager& ul_lc_mng_) : + cell_cfg_common(cell_cfg_common_), drx_cfg(drx_cfg_), ul_lc_mng(ul_lc_mng_) +{ + if (drx_cfg.has_value()) { + const subcarrier_spacing scs = cell_cfg_common.dl_cfg_common.init_dl_bwp.generic_params.scs; + const unsigned nof_slots_per_sf = get_nof_slots_per_subframe(scs); + + active_window_period = drx_cfg.value().long_cycle.count() * nof_slots_per_sf; + unsigned win_start = drx_cfg.value().long_start_offset.count() * nof_slots_per_sf; + active_window = {win_start, win_start + drx_cfg.value().on_duration_timer.count() * nof_slots_per_sf}; + inactivity_dur = drx_cfg.value().inactivity_timer.count() * nof_slots_per_sf; + } +} + +void ue_drx_controller::slot_indication(slot_point dl_slot) +{ + if (dl_slot >= active_time_end) { + active_time_end = {}; + } + + const unsigned slot_mod = dl_slot.to_uint() % active_window_period; + if (slot_mod >= active_window.start() and slot_mod < active_window.stop()) { + // "the Active Time includes the time while [...] drx-onDuration [...] is running." + slot_point new_end = dl_slot + (active_window.stop() - slot_mod); + if (not active_time_end.valid() or new_end > active_time_end) { + active_time_end = new_end; + } + } +} + +bool ue_drx_controller::is_pdcch_enabled(slot_point dl_slot) const +{ + if (not drx_cfg.has_value()) { + return true; + } + return is_active_time(dl_slot); +} + +bool ue_drx_controller::is_active_time(slot_point dl_slot) const +{ + if (active_time_end.valid()) { + // active_time_end is set during drx-onDurationTimer or drx-InactivityTimer. + return true; + } + + if (ul_lc_mng.has_pending_sr()) { + // "the Active Time includes the time while [...] a Scheduling Request is sent on PUCCH and is pending" + return true; + } + + return false; +} + +void ue_drx_controller::on_new_pdcch_alloc(slot_point pdcch_slot) +{ + if (not drx_cfg.has_value()) { + return; + } + + if (is_active_time(pdcch_slot)) { + // "1> if the MAC entity is in Active Time + // " 2> if the PDCCH indicates a new transmission (DL or UL) [...] start or restart drx-InactivityTimer in the + // first symbol after the end of the PDCCH reception." + active_time_end = pdcch_slot + inactivity_dur; + } +} + +void ue_drx_controller::on_con_res_start(slot_point msg3_slot_rx) +{ + if (not drx_cfg.has_value()) { + return; + } + + const subcarrier_spacing scs = cell_cfg_common.dl_cfg_common.init_dl_bwp.generic_params.scs; + const unsigned conres_slots = cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common->ra_con_res_timer.count() * + get_nof_slots_per_subframe(scs); + + slot_point new_time_end = msg3_slot_rx + conres_slots; + + if (not active_time_end.valid() or active_time_end < new_time_end) { + // "the Active Time includes the time while [...] ra-ContentionResolutionTimer [...] is running." + active_time_end = new_time_end; + } +} diff --git a/lib/scheduler/ue_context/ue_drx_controller.h b/lib/scheduler/ue_context/ue_drx_controller.h new file mode 100644 index 0000000000..cb32f8ae35 --- /dev/null +++ b/lib/scheduler/ue_context/ue_drx_controller.h @@ -0,0 +1,58 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "srsran/ran/drx_config.h" +#include "srsran/ran/slot_point.h" +#include + +namespace srsran { + +class cell_configuration; +class ue_cell_configuration; +class ul_logical_channel_manager; + +/// Class that determines UE DRX active time. +class ue_drx_controller +{ +public: + ue_drx_controller(const cell_configuration& cell_cfg_common_, + const std::optional& drx_cfg_, + const ul_logical_channel_manager& ul_lc_mng); + + /// Update DRX controller state. + void slot_indication(slot_point dl_slot); + + /// Determines whether the PDCCH can be allocated for a given slot. + bool is_pdcch_enabled(slot_point dl_slot) const; + + /// Update DRX active time based on new PDCCH allocations. + void on_new_pdcch_alloc(slot_point dl_slot); + + /// Update DRX active time based on ContentionResolutionTimer. + void on_con_res_start(slot_point msg3_slot_rx); + +private: + /// Whether the UE is within DRX active time. + bool is_active_time(slot_point dl_slot) const; + + const cell_configuration& cell_cfg_common; + const std::optional& drx_cfg; + const ul_logical_channel_manager& ul_lc_mng; + unsigned active_window_period; + interval active_window; + unsigned inactivity_dur; + + // End slot for the active window. When invalid, the UE is not in active window. + slot_point active_time_end; +}; + +} // namespace srsran \ No newline at end of file From 83e707f37b4e4c6f165008759856e9c4c19bc63e Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 7 Nov 2024 17:13:08 +0100 Subject: [PATCH 19/26] sched: integrate ue_drx_controller with the scheduler policy --- lib/scheduler/policy/scheduler_time_pf.cpp | 8 ++++---- lib/scheduler/policy/scheduler_time_rr.cpp | 10 +++++----- lib/scheduler/ue_context/ue.cpp | 3 ++- lib/scheduler/ue_context/ue_cell.cpp | 15 +++++++++++++-- lib/scheduler/ue_context/ue_cell.h | 8 ++++++-- .../scheduler/ue_scheduling/ue_cell_test.cpp | 12 ++++++++---- 6 files changed, 38 insertions(+), 18 deletions(-) diff --git a/lib/scheduler/policy/scheduler_time_pf.cpp b/lib/scheduler/policy/scheduler_time_pf.cpp index 966589137f..2779dfe56b 100644 --- a/lib/scheduler/policy/scheduler_time_pf.cpp +++ b/lib/scheduler/policy/scheduler_time_pf.cpp @@ -43,7 +43,7 @@ dl_alloc_result scheduler_time_pf::schedule_dl_retxs(ue_pdsch_allocator& // [Implementation-defined] Skip UE if PDCCH is already allocated for this UE in this slot. if (res_grid.has_ue_dl_pdcch(ue_cc.cell_index, u.crnti()) or - not ue_cc.is_dl_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index))) { + not ue_cc.is_pdcch_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index))) { continue; } @@ -137,7 +137,7 @@ ul_alloc_result scheduler_time_pf::schedule_ul_retxs(ue_pusch_allocator& "Policy scheduler called for UE={} in fallback", ue_cc.ue_index); - if (not ue_cc.is_dl_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index)) or + if (not ue_cc.is_pdcch_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index)) or not ue_cc.is_ul_enabled(slice_candidate.get_slot_tx())) { // Either the PDCCH slot or PUSCH slots are not available. continue; @@ -335,7 +335,7 @@ void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u, srsran_assert(ue_cc->is_active() and not ue_cc->is_in_fallback_mode(), "Policy scheduler called for UE={} in fallback", ue_cc->ue_index); - if (not ue_cc->is_dl_enabled(pdcch_slot) or not ue_cc->is_dl_enabled(pdsch_slot)) { + if (not ue_cc->is_pdcch_enabled(pdcch_slot) or not ue_cc->is_pdsch_enabled(pdsch_slot)) { // Cannot allocate PDCCH/PDSCH for this UE in this slot. return; } @@ -411,7 +411,7 @@ void scheduler_time_pf::ue_ctxt::compute_ul_prio(const slice_ue& u, srsran_assert(ue_cc->is_active() and not ue_cc->is_in_fallback_mode(), "Policy scheduler called for UE={} in fallback", ue_cc->ue_index); - if (not ue_cc->is_dl_enabled(pdcch_slot) or not ue_cc->is_ul_enabled(pusch_slot)) { + if (not ue_cc->is_pdcch_enabled(pdcch_slot) or not ue_cc->is_ul_enabled(pusch_slot)) { // Cannot allocate PDCCH/PUSCH for this UE in the provided slots. return; } diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index 2f8fe7703c..0352b35d09 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -251,7 +251,7 @@ static dl_alloc_result alloc_dl_retxs(const slice_ue_repository& ue_db, // [Implementation-defined] Skip UE if PDCCH is already allocated for this UE in this slot. if (res_grid.has_ue_dl_pdcch(ue_cc.cell_index, u.crnti()) or - not ue_cc.is_dl_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index))) { + not ue_cc.is_pdcch_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index))) { continue; } @@ -292,8 +292,8 @@ static dl_alloc_result alloc_dl_ue_newtx(const slice_ue& u, ue_cc.ue_index); if (res_grid.has_ue_dl_pdcch(ue_cc.cell_index, u.crnti()) or - not ue_cc.is_dl_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index)) or - not ue_cc.is_dl_enabled(slice_candidate.get_slot_tx())) { + not ue_cc.is_pdcch_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index)) or + not ue_cc.is_pdsch_enabled(slice_candidate.get_slot_tx())) { // UE is either already allocated for this slot (e.g. a reTx already took place) or it is not active. return {alloc_status::skip_ue}; } @@ -332,7 +332,7 @@ static ul_alloc_result alloc_ul_retxs(const slice_ue_repository& ue_db, "policy scheduler called for UE={} in fallback", ue_cc.ue_index); - if (not ue_cc.is_dl_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index)) or + if (not ue_cc.is_pdcch_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index)) or not ue_cc.is_ul_enabled(slice_candidate.get_slot_tx())) { // Either the PDCCH slot or PUSCH slots are not available. continue; @@ -376,7 +376,7 @@ static ul_alloc_result alloc_ul_ue_newtx(const slice_ue& u, "policy scheduler called for UE={} in fallback", ue_cc.ue_index); - if (not ue_cc.is_dl_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index)) or + if (not ue_cc.is_pdcch_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index)) or not ue_cc.is_ul_enabled(slice_candidate.get_slot_tx())) { // Either the PDCCH slot or PUSCH slots are not available. continue; diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index 9e87087069..043c63fed8 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -109,7 +109,8 @@ void ue::handle_reconfiguration_request(const ue_reconf_command& cmd) du_cell_index_t cell_index = ue_ded_cfg->ue_cell_cfg(to_ue_cell_index(ue_cell_index)).cell_cfg_common.cell_index; auto& ue_cell_inst = ue_du_cells[cell_index]; if (ue_cell_inst == nullptr) { - ue_cell_inst = std::make_unique(ue_index, crnti, ue_ded_cfg->ue_cell_cfg(cell_index), pcell_harq_pool); + ue_cell_inst = + std::make_unique(ue_index, crnti, ue_ded_cfg->ue_cell_cfg(cell_index), pcell_harq_pool, drx); if (ue_cell_index >= ue_cells.size()) { ue_cells.resize(ue_cell_index + 1); } diff --git a/lib/scheduler/ue_context/ue_cell.cpp b/lib/scheduler/ue_context/ue_cell.cpp index fa43384cd1..9c15b403b8 100644 --- a/lib/scheduler/ue_context/ue_cell.cpp +++ b/lib/scheduler/ue_context/ue_cell.cpp @@ -13,6 +13,7 @@ #include "../support/mcs_calculator.h" #include "../support/pdcch_aggregation_level_calculator.h" #include "../support/prbs_calculator.h" +#include "ue_drx_controller.h" #include "srsran/ran/sch/tbs_calculator.h" #include "srsran/scheduler/scheduler_feedback_handler.h" #include "srsran/srslog/srslog.h" @@ -29,7 +30,8 @@ constexpr unsigned DEFAULT_NOF_DL_HARQS = 8; ue_cell::ue_cell(du_ue_index_t ue_index_, rnti_t crnti_val, const ue_cell_configuration& ue_cell_cfg_, - cell_harq_manager& cell_harq_pool) : + cell_harq_manager& cell_harq_pool, + ue_drx_controller& drx_ctrl_) : ue_index(ue_index_), cell_index(ue_cell_cfg_.cell_cfg_common.cell_index), harqs(cell_harq_pool.add_ue(ue_index, @@ -42,6 +44,7 @@ ue_cell::ue_cell(du_ue_index_t ue_index_, cell_cfg(ue_cell_cfg_.cell_cfg_common), ue_cfg(&ue_cell_cfg_), expert_cfg(cell_cfg.expert_cfg.ue), + drx_ctrl(drx_ctrl_), logger(srslog::fetch_basic_logger("SCHED")), channel_state(cell_cfg.expert_cfg.ue, ue_cfg->get_nof_dl_ports()), ue_mcs_calculator(ue_cell_cfg_.cell_cfg_common, channel_state) @@ -111,7 +114,15 @@ void ue_cell::set_fallback_state(bool set_fallback) logger.debug("ue={} rnti={}: {} fallback mode", ue_index, rnti(), in_fallback_mode ? "Entering" : "Leaving"); } -bool ue_cell::is_dl_enabled(slot_point dl_slot) const +bool ue_cell::is_pdcch_enabled(slot_point dl_slot) const +{ + if (not active) { + return false; + } + return cfg().is_dl_enabled(dl_slot) and drx_ctrl.is_pdcch_enabled(dl_slot); +} + +bool ue_cell::is_pdsch_enabled(slot_point dl_slot) const { if (not active) { return false; diff --git a/lib/scheduler/ue_context/ue_cell.h b/lib/scheduler/ue_context/ue_cell.h index 985a9813fd..3b64334add 100644 --- a/lib/scheduler/ue_context/ue_cell.h +++ b/lib/scheduler/ue_context/ue_cell.h @@ -23,6 +23,7 @@ namespace srsran { struct ul_crc_pdu_indication; +class ue_drx_controller; struct grant_prbs_mcs { /// MCS to use for the UE's PxSCH. @@ -44,7 +45,8 @@ class ue_cell ue_cell(du_ue_index_t ue_index_, rnti_t crnti_val, const ue_cell_configuration& ue_cell_cfg_, - cell_harq_manager& cell_harq_pool); + cell_harq_manager& cell_harq_pool, + ue_drx_controller& drx_ctrl); const du_ue_index_t ue_index; const du_cell_index_t cell_index; @@ -72,7 +74,8 @@ class ue_cell void set_fallback_state(bool in_fallback); - bool is_dl_enabled(slot_point dl_slot) const; + bool is_pdcch_enabled(slot_point dl_slot) const; + bool is_pdsch_enabled(slot_point dl_slot) const; bool is_ul_enabled(slot_point ul_slot) const; struct dl_ack_info_result { @@ -156,6 +159,7 @@ class ue_cell const cell_configuration& cell_cfg; const ue_cell_configuration* ue_cfg; const scheduler_ue_expert_config& expert_cfg; + ue_drx_controller& drx_ctrl; srslog::basic_logger& logger; /// \brief Whether cell is currently active. diff --git a/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp index 4c73caff3e..01d776cdba 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp @@ -9,6 +9,8 @@ */ #include "lib/scheduler/ue_context/ue_cell.h" +#include "lib/scheduler/ue_context/ue_drx_controller.h" +#include "lib/scheduler/ue_context/ul_logical_channel_manager.h" #include "tests/unittests/scheduler/test_utils/config_generators.h" #include @@ -79,11 +81,13 @@ class ue_cell_tester : public ::testing::Test serving_cell_config serv_cell_cfg; ue_cell_configuration ue_cc_cfg; cell_harq_manager cell_harqs{1, MAX_NOF_HARQS}; + ul_logical_channel_manager ul_lc_ch_mng; + ue_drx_controller drx_controller{cell_cfg, std::nullopt, ul_lc_ch_mng}; }; TEST_F(ue_cell_tester, when_dl_nof_prb_allocated_increases_estimated_dl_rate_increases) { - ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, cell_harqs}; + ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, cell_harqs, drx_controller}; double current_rate = 0; @@ -108,7 +112,7 @@ TEST_F(ue_cell_tester, when_mcs_increases_estimated_dl_rate_increases) // Maximum MCS value for 64QAM MCS table. const sch_mcs_index max_mcs = 28; - ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, cell_harqs}; + ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, cell_harqs, drx_controller}; double current_rate = 0; @@ -132,7 +136,7 @@ TEST_F(ue_cell_tester, when_mcs_increases_estimated_dl_rate_increases) TEST_F(ue_cell_tester, when_ul_nof_prb_allocated_increases_estimated_ul_rate_increases) { - ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, cell_harqs}; + ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, cell_harqs, drx_controller}; double current_rate = 0; @@ -157,7 +161,7 @@ TEST_F(ue_cell_tester, when_mcs_increases_estimated_ul_rate_increases) // Maximum MCS value for 64QAM MCS table. const sch_mcs_index max_mcs = 28; - ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, cell_harqs}; + ue_cell ue_cc{to_du_ue_index(0), to_rnti(0x4601), ue_cc_cfg, cell_harqs, drx_controller}; double current_rate = 0; From 223ce539033f79825d8fff8cb6468508355e7234 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 7 Nov 2024 18:00:38 +0100 Subject: [PATCH 20/26] sched: update ue_grid_allocator and fallback scheduler to extend DRX active time --- lib/scheduler/ue_context/ue.cpp | 1 + lib/scheduler/ue_context/ue.h | 3 +++ .../ue_scheduling/ue_cell_grid_allocator.cpp | 9 ++++++++- .../ue_scheduling/ue_fallback_scheduler.cpp | 12 ++++++++++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index 043c63fed8..bcfe115c92 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -57,6 +57,7 @@ void ue::slot_indication(slot_point sl_tx) } ta_mgr.slot_indication(sl_tx); + drx.slot_indication(sl_tx); } void ue::deactivate() diff --git a/lib/scheduler/ue_context/ue.h b/lib/scheduler/ue_context/ue.h index 1608f234b0..ec37365855 100644 --- a/lib/scheduler/ue_context/ue.h +++ b/lib/scheduler/ue_context/ue.h @@ -174,6 +174,9 @@ class ue /// \brief Returns whether a SR indication handling is pending. bool has_pending_sr() const; + /// \brief Retrieves UE DRX controller. + ue_drx_controller& drx_controller() { return drx; } + /// \brief Defines the list of subPDUs, including LCID and payload size, that will compose the transport block. /// \return Returns the number of bytes reserved in the TB for subPDUs (other than padding). /// \remark Excludes SRB0. diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index 1639c9563b..98311cc852 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -12,6 +12,7 @@ #include "../support/dci_builder.h" #include "../support/mcs_calculator.h" #include "../support/sched_result_helpers.h" +#include "../ue_context/ue_drx_controller.h" #include "ue_pdsch_alloc_param_candidate_searcher.h" #include "ue_pusch_alloc_param_candidate_searcher.h" #include "srsran/ran/pdcch/coreset.h" @@ -92,7 +93,7 @@ dl_alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& // Fetch PDCCH resource grid allocator. cell_slot_resource_allocator& pdcch_alloc = get_res_alloc(grant.cell_index)[0]; - if (not cell_cfg.is_dl_enabled(pdcch_alloc.slot)) { + if (not ue_cc->is_pdcch_enabled(pdcch_alloc.slot)) { logger.warning("ue={} rnti={}: Failed to allocate PDSCH. Cause: DL is not active in the PDCCH slot={}", u.ue_index, u.crnti, @@ -476,6 +477,9 @@ dl_alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& h_dl->save_grant_params(pdsch_sched_ctx, msg.pdsch_cfg); + // Update DRX state given the new allocation. + u.drx_controller().on_new_pdcch_alloc(pdcch_alloc.slot); + return {alloc_status::success, h_dl->get_grant_params().tbs_bytes, crbs.length(), @@ -998,6 +1002,9 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice // In case there is a SR pending. Reset it. u.reset_sr_indication(); + // Update DRX state given the new allocation. + u.drx_controller().on_new_pdcch_alloc(pdcch_alloc.slot); + return {alloc_status::success, h_ul->get_grant_params().tbs_bytes, crbs.length()}; } diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 920b6262b7..50f4ad05f2 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -722,6 +722,9 @@ ue_fallback_scheduler::schedule_dl_conres_ce(ue& // Mark resources as occupied in the Resource grid. pdsch_alloc.dl_res_grid.fill(grant_info{scs, pdsch_td_cfg.symbols, ue_grant_crbs}); + // Update DRX controller state. + u.drx_controller().on_new_pdcch_alloc(pdcch_alloc.slot); + auto result = fill_dl_srb_grant(u, pdsch_alloc.slot, h_dl_retx, @@ -931,6 +934,9 @@ ue_fallback_scheduler::schedule_dl_srb0(ue& u, // Mark resources as occupied in the ResourceGrid. pdsch_alloc.dl_res_grid.fill(grant_info{scs, pdsch_td_cfg.symbols, ue_grant_crbs}); + // Update DRX controller state. + u.drx_controller().on_new_pdcch_alloc(pdcch_alloc.slot); + std::optional is_srb0; if (not result.is_srb_data_pending) { is_srb0 = true; @@ -1149,6 +1155,9 @@ ue_fallback_scheduler::schedule_dl_srb1(ue& u, // Mark resources as occupied in the ResourceGrid. pdsch_alloc.dl_res_grid.fill(grant_info{scs, pdsch_td_cfg.symbols, ue_grant_crbs}); + // Update DRX controller state. + u.drx_controller().on_new_pdcch_alloc(pdcch_alloc.slot); + auto [nof_srb1_scheduled_bytes, h_dl] = fill_dl_srb_grant(u, pdsch_alloc.slot, h_dl_retx, @@ -1564,6 +1573,9 @@ ue_fallback_scheduler::schedule_ul_srb(ue& pusch_alloc.ul_res_grid.fill( grant_info{cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.scs, pusch_td.symbols, ue_grant_crbs}); + // Update DRX controller state. + u.drx_controller().on_new_pdcch_alloc(pdcch_alloc.slot); + fill_ul_srb_grant(u, pdcch_alloc.slot, h_ul_retx, From 97e0fea30874c547074a571040852ef2071905b7 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 8 Nov 2024 10:27:44 +0100 Subject: [PATCH 21/26] sched: handling of ra-ContentionResolutionTimer in DRX config --- include/srsran/mac/mac_ue_configurator.h | 1 + include/srsran/scheduler/scheduler_configurator.h | 2 ++ lib/du/du_high/du_manager/du_ue/du_ue_manager.cpp | 2 +- .../procedures/ue_creation_procedure.cpp | 3 ++- .../du_manager/procedures/ue_creation_procedure.h | 3 +++ lib/mac/mac_sched/srsran_scheduler_adapter.cpp | 1 + lib/scheduler/config/sched_config_manager.h | 2 ++ lib/scheduler/ue_context/ue.cpp | 2 +- lib/scheduler/ue_context/ue.h | 1 + lib/scheduler/ue_context/ue_drx_controller.cpp | 15 ++++++++++----- lib/scheduler/ue_context/ue_drx_controller.h | 6 ++++-- lib/scheduler/ue_scheduling/ue_event_manager.cpp | 3 ++- .../ue_scheduling/ue_fallback_scheduler.cpp | 2 ++ .../scheduler/uci_and_pucch/uci_test_utils.cpp | 2 +- .../scheduler/ue_scheduling/ue_cell_test.cpp | 2 +- 15 files changed, 34 insertions(+), 13 deletions(-) diff --git a/include/srsran/mac/mac_ue_configurator.h b/include/srsran/mac/mac_ue_configurator.h index eaa5158645..4683775a17 100644 --- a/include/srsran/mac/mac_ue_configurator.h +++ b/include/srsran/mac/mac_ue_configurator.h @@ -66,6 +66,7 @@ struct mac_ue_create_request { physical_cell_group_config phy_cell_group_cfg; bool initial_fallback = true; const byte_buffer* ul_ccch_msg = nullptr; + slot_point ul_ccch_slot_rx; // Scheduler-only params. sched_ue_config_request sched_cfg; diff --git a/include/srsran/scheduler/scheduler_configurator.h b/include/srsran/scheduler/scheduler_configurator.h index 5d47872cc4..b15c18c50e 100644 --- a/include/srsran/scheduler/scheduler_configurator.h +++ b/include/srsran/scheduler/scheduler_configurator.h @@ -153,6 +153,8 @@ struct sched_ue_creation_request_message { rnti_t crnti; /// Whether the UE starts in fallback mode, i.e. without using its dedicated configuration. bool starts_in_fallback; + /// Slot at which UL-CCCH message was received, in case of RA-based UE creation. Invalid, otherwise. + slot_point ul_ccch_slot_rx; /// Configuration to be applied to the new UE. sched_ue_config_request cfg; /// Time Alignment Group configuration. diff --git a/lib/du/du_high/du_manager/du_ue/du_ue_manager.cpp b/lib/du/du_high/du_manager/du_ue/du_ue_manager.cpp index a3cba3b9d9..a6a0dd9dee 100644 --- a/lib/du/du_high/du_manager/du_ue/du_ue_manager.cpp +++ b/lib/du/du_high/du_manager/du_ue/du_ue_manager.cpp @@ -59,7 +59,7 @@ void du_ue_manager::handle_ue_create_request(const ul_ccch_indication_message& m // Enqueue UE creation procedure ue_ctrl_loop[ue_idx_candidate].schedule( - du_ue_creation_request{ue_idx_candidate, msg.cell_index, msg.tc_rnti, msg.subpdu.copy()}, + du_ue_creation_request{ue_idx_candidate, msg.cell_index, msg.tc_rnti, msg.subpdu.copy(), msg.slot_rx}, *this, cfg, cell_res_alloc); diff --git a/lib/du/du_high/du_manager/procedures/ue_creation_procedure.cpp b/lib/du/du_high/du_manager/procedures/ue_creation_procedure.cpp index 8cd8b9fbf8..9075e099c6 100644 --- a/lib/du/du_high/du_manager/procedures/ue_creation_procedure.cpp +++ b/lib/du/du_high/du_manager/procedures/ue_creation_procedure.cpp @@ -209,7 +209,8 @@ async_task ue_creation_procedure::create_mac_ue() lc.ul_bearer = &bearer.second->connector.mac_rx_sdu_notifier; lc.dl_bearer = &bearer.second->connector.mac_tx_sdu_notifier; } - mac_ue_create_msg.ul_ccch_msg = not req.ul_ccch_msg.empty() ? &req.ul_ccch_msg : nullptr; + mac_ue_create_msg.ul_ccch_msg = not req.ul_ccch_msg.empty() ? &req.ul_ccch_msg : nullptr; + mac_ue_create_msg.ul_ccch_slot_rx = req.slot_rx; // Create Scheduler UE Config Request that will be embedded in the mac UE creation request. mac_ue_create_msg.sched_cfg = create_scheduler_ue_config_request(*ue_ctx, *ue_ctx->resources); diff --git a/lib/du/du_high/du_manager/procedures/ue_creation_procedure.h b/lib/du/du_high/du_manager/procedures/ue_creation_procedure.h index 0596189d94..a2d38581c2 100644 --- a/lib/du/du_high/du_manager/procedures/ue_creation_procedure.h +++ b/lib/du/du_high/du_manager/procedures/ue_creation_procedure.h @@ -29,6 +29,9 @@ struct du_ue_creation_request { rnti_t tc_rnti; /// \brief UL-CCCH message received from the UE in Msg3. Empty if the UE is created by upper layers. byte_buffer ul_ccch_msg; + /// \brief Slot at which the UL-CCCH message was received in the PUSCH. Invalid slot if the UE is created by upper + /// layers. + slot_point slot_rx; }; /// \brief Handles the creation of a UE and respective bearers in the DU UE manager, MAC, F1. diff --git a/lib/mac/mac_sched/srsran_scheduler_adapter.cpp b/lib/mac/mac_sched/srsran_scheduler_adapter.cpp index ec1bcaeffc..1a3e216579 100644 --- a/lib/mac/mac_sched/srsran_scheduler_adapter.cpp +++ b/lib/mac/mac_sched/srsran_scheduler_adapter.cpp @@ -20,6 +20,7 @@ static sched_ue_creation_request_message make_scheduler_ue_creation_request(cons ret.ue_index = request.ue_index; ret.crnti = request.crnti; ret.starts_in_fallback = request.initial_fallback; + ret.ul_ccch_slot_rx = request.ul_ccch_slot_rx; ret.cfg = request.sched_cfg; ret.tag_config = request.mac_cell_group_cfg.tag_config; return ret; diff --git a/lib/scheduler/config/sched_config_manager.h b/lib/scheduler/config/sched_config_manager.h index 333e43a0bf..bbddc7ed08 100644 --- a/lib/scheduler/config/sched_config_manager.h +++ b/lib/scheduler/config/sched_config_manager.h @@ -40,6 +40,7 @@ class ue_config_update_event du_ue_index_t get_ue_index() const { return ue_index; } const ue_configuration& next_config() const { return *next_ded_cfg; } std::optional get_fallback_command() const { return set_fallback_mode; } + slot_point get_ul_ccch_slot_rx() const { return ul_ccch_slot_rx; } void notify_completion(); @@ -49,6 +50,7 @@ class ue_config_update_event std::unique_ptr parent; std::unique_ptr next_ded_cfg; std::optional set_fallback_mode; + slot_point ul_ccch_slot_rx; }; /// Event to delete a UE in the scheduler. diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index bcfe115c92..125b694ef0 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -24,7 +24,7 @@ ue::ue(const ue_creation_command& cmd) : pcell_harq_pool(cmd.pcell_harq_pool), logger(srslog::fetch_basic_logger("SCHED")), ta_mgr(expert_cfg, cell_cfg_common.ul_cfg_common.init_ul_bwp.generic_params.scs, &dl_lc_ch_mgr), - drx(cell_cfg_common, cmd.cfg.drx_cfg(), ul_lc_ch_mgr) + drx(cell_cfg_common, cmd.cfg.drx_cfg(), ul_lc_ch_mgr, cmd.ul_ccch_slot_rx) { // Apply configuration. handle_reconfiguration_request(ue_reconf_command{cmd.cfg}); diff --git a/lib/scheduler/ue_context/ue.h b/lib/scheduler/ue_context/ue.h index ec37365855..83053e4244 100644 --- a/lib/scheduler/ue_context/ue.h +++ b/lib/scheduler/ue_context/ue.h @@ -25,6 +25,7 @@ struct ue_creation_command { const ue_configuration& cfg; bool starts_in_fallback; cell_harq_manager& pcell_harq_pool; + slot_point ul_ccch_slot_rx; }; /// Parameters used to reconfigure a UE. diff --git a/lib/scheduler/ue_context/ue_drx_controller.cpp b/lib/scheduler/ue_context/ue_drx_controller.cpp index 0eb66a5772..8e82e02c42 100644 --- a/lib/scheduler/ue_context/ue_drx_controller.cpp +++ b/lib/scheduler/ue_context/ue_drx_controller.cpp @@ -16,8 +16,9 @@ using namespace srsran; ue_drx_controller::ue_drx_controller(const cell_configuration& cell_cfg_common_, const std::optional& drx_cfg_, - const ul_logical_channel_manager& ul_lc_mng_) : - cell_cfg_common(cell_cfg_common_), drx_cfg(drx_cfg_), ul_lc_mng(ul_lc_mng_) + const ul_logical_channel_manager& ul_lc_mng_, + slot_point ul_ccch_slot_rx_) : + cell_cfg_common(cell_cfg_common_), drx_cfg(drx_cfg_), ul_lc_mng(ul_lc_mng_), ul_ccch_slot_rx(ul_ccch_slot_rx_) { if (drx_cfg.has_value()) { const subcarrier_spacing scs = cell_cfg_common.dl_cfg_common.init_dl_bwp.generic_params.scs; @@ -32,7 +33,11 @@ ue_drx_controller::ue_drx_controller(const cell_configuration& cell_cfg_ void ue_drx_controller::slot_indication(slot_point dl_slot) { - if (dl_slot >= active_time_end) { + if (not drx_cfg.has_value()) { + return; + } + + if (active_time_end.valid() and dl_slot >= active_time_end) { active_time_end = {}; } @@ -83,7 +88,7 @@ void ue_drx_controller::on_new_pdcch_alloc(slot_point pdcch_slot) } } -void ue_drx_controller::on_con_res_start(slot_point msg3_slot_rx) +void ue_drx_controller::on_con_res_start() { if (not drx_cfg.has_value()) { return; @@ -93,7 +98,7 @@ void ue_drx_controller::on_con_res_start(slot_point msg3_slot_rx) const unsigned conres_slots = cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common->ra_con_res_timer.count() * get_nof_slots_per_subframe(scs); - slot_point new_time_end = msg3_slot_rx + conres_slots; + slot_point new_time_end = ul_ccch_slot_rx + conres_slots; if (not active_time_end.valid() or active_time_end < new_time_end) { // "the Active Time includes the time while [...] ra-ContentionResolutionTimer [...] is running." diff --git a/lib/scheduler/ue_context/ue_drx_controller.h b/lib/scheduler/ue_context/ue_drx_controller.h index cb32f8ae35..444a185445 100644 --- a/lib/scheduler/ue_context/ue_drx_controller.h +++ b/lib/scheduler/ue_context/ue_drx_controller.h @@ -26,7 +26,8 @@ class ue_drx_controller public: ue_drx_controller(const cell_configuration& cell_cfg_common_, const std::optional& drx_cfg_, - const ul_logical_channel_manager& ul_lc_mng); + const ul_logical_channel_manager& ul_lc_mng, + slot_point ul_ccch_slot_rx); /// Update DRX controller state. void slot_indication(slot_point dl_slot); @@ -38,7 +39,7 @@ class ue_drx_controller void on_new_pdcch_alloc(slot_point dl_slot); /// Update DRX active time based on ContentionResolutionTimer. - void on_con_res_start(slot_point msg3_slot_rx); + void on_con_res_start(); private: /// Whether the UE is within DRX active time. @@ -47,6 +48,7 @@ class ue_drx_controller const cell_configuration& cell_cfg_common; const std::optional& drx_cfg; const ul_logical_channel_manager& ul_lc_mng; + slot_point ul_ccch_slot_rx; unsigned active_window_period; interval active_window; unsigned inactivity_dur; diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index 6e1d378907..091226406c 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -193,7 +193,8 @@ void ue_event_manager::handle_ue_creation(ue_config_update_event ev) std::unique_ptr u = std::make_unique( ue_creation_command{ev.next_config(), ev.get_fallback_command().has_value() and ev.get_fallback_command().value(), - *du_cells[ev.next_config().pcell_common_cfg().cell_index].cell_harqs}); + *du_cells[ev.next_config().pcell_common_cfg().cell_index].cell_harqs, + ev.get_ul_ccch_slot_rx()}); const du_ue_index_t ue_idx = u->ue_index; auto handle_ue_creation_impl = [this, u = std::move(u), ev = std::move(ev)]() mutable { diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 50f4ad05f2..fa8c7dd61e 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -144,6 +144,8 @@ void ue_fallback_scheduler::handle_conres_indication(du_ue_index_t ue_index) logger.error("ue_index={} not found in the scheduler", ue_index); return; } + auto& u = ues[ue_index]; + u.drx_controller().on_con_res_start(); auto ue_it = std::find_if(pending_dl_ues_new_tx.begin(), pending_dl_ues_new_tx.end(), diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp index 08c2fc55cc..796dc614b0 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp @@ -216,7 +216,7 @@ test_bench::test_bench(const test_bench_params& params, } ue_ded_cfgs.push_back(std::make_unique(ue_req.ue_index, ue_req.crnti, cell_cfg_list, ue_req.cfg)); - ues.add_ue(std::make_unique(ue_creation_command{*ue_ded_cfgs.back(), ue_req.starts_in_fallback, cell_harqs})); + ues.add_ue(std::make_unique(ue_creation_command{*ue_ded_cfgs.back(), ue_req.starts_in_fallback, cell_harqs, {}})); uci_sched.add_ue(ues[ue_req.ue_index].get_pcell().cfg()); last_allocated_rnti = ue_req.crnti; last_allocated_ue_idx = main_ue_idx; diff --git a/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp index 01d776cdba..cd27b3c1d0 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp @@ -82,7 +82,7 @@ class ue_cell_tester : public ::testing::Test ue_cell_configuration ue_cc_cfg; cell_harq_manager cell_harqs{1, MAX_NOF_HARQS}; ul_logical_channel_manager ul_lc_ch_mng; - ue_drx_controller drx_controller{cell_cfg, std::nullopt, ul_lc_ch_mng}; + ue_drx_controller drx_controller{cell_cfg, std::nullopt, ul_lc_ch_mng, {}}; }; TEST_F(ue_cell_tester, when_dl_nof_prb_allocated_increases_estimated_dl_rate_increases) From f139e55ee85bca660698621f3c93fe2192d96f86 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 8 Nov 2024 12:20:11 +0100 Subject: [PATCH 22/26] sched: basic ue drx controller unit test --- lib/scheduler/CMakeLists.txt | 3 +- lib/scheduler/ue_context/CMakeLists.txt | 2 +- lib/scheduler/ue_context/ue.cpp | 6 +- .../ue_context/ue_drx_controller.cpp | 17 ++-- lib/scheduler/ue_context/ue_drx_controller.h | 8 +- tests/unittests/scheduler/CMakeLists.txt | 1 + .../scheduler/ue_context/CMakeLists.txt | 16 ++++ .../ue_context/ue_drx_controller_test.cpp | 81 +++++++++++++++++++ .../scheduler/ue_scheduling/ue_cell_test.cpp | 6 +- 9 files changed, 124 insertions(+), 16 deletions(-) create mode 100644 tests/unittests/scheduler/ue_context/CMakeLists.txt create mode 100644 tests/unittests/scheduler/ue_context/ue_drx_controller_test.cpp diff --git a/lib/scheduler/CMakeLists.txt b/lib/scheduler/CMakeLists.txt index 9825cd43d0..2a9df3162a 100644 --- a/lib/scheduler/CMakeLists.txt +++ b/lib/scheduler/CMakeLists.txt @@ -39,6 +39,5 @@ add_library(srsran_sched STATIC ${SOURCES} $ $ $ - $ $) -target_link_libraries(srsran_sched srsran_ran sched_config sched_support scheduler_logger) +target_link_libraries(srsran_sched srsran_ran sched_config sched_ue_context sched_support scheduler_logger) diff --git a/lib/scheduler/ue_context/CMakeLists.txt b/lib/scheduler/ue_context/CMakeLists.txt index 5a4f4ecbc2..7533407c17 100644 --- a/lib/scheduler/ue_context/CMakeLists.txt +++ b/lib/scheduler/ue_context/CMakeLists.txt @@ -16,4 +16,4 @@ set(SOURCES ue.cpp ue_cell.cpp) -add_library(sched_ue_context OBJECT ${SOURCES}) +add_library(sched_ue_context STATIC ${SOURCES}) diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index 125b694ef0..f53b33225f 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -24,7 +24,11 @@ ue::ue(const ue_creation_command& cmd) : pcell_harq_pool(cmd.pcell_harq_pool), logger(srslog::fetch_basic_logger("SCHED")), ta_mgr(expert_cfg, cell_cfg_common.ul_cfg_common.init_ul_bwp.generic_params.scs, &dl_lc_ch_mgr), - drx(cell_cfg_common, cmd.cfg.drx_cfg(), ul_lc_ch_mgr, cmd.ul_ccch_slot_rx) + drx(cell_cfg_common.ul_cfg_common.init_ul_bwp.generic_params.scs, + cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common->ra_con_res_timer, + cmd.cfg.drx_cfg(), + ul_lc_ch_mgr, + cmd.ul_ccch_slot_rx) { // Apply configuration. handle_reconfiguration_request(ue_reconf_command{cmd.cfg}); diff --git a/lib/scheduler/ue_context/ue_drx_controller.cpp b/lib/scheduler/ue_context/ue_drx_controller.cpp index 8e82e02c42..df81ae01ad 100644 --- a/lib/scheduler/ue_context/ue_drx_controller.cpp +++ b/lib/scheduler/ue_context/ue_drx_controller.cpp @@ -9,20 +9,23 @@ */ #include "ue_drx_controller.h" -#include "../config/ue_configuration.h" #include "ul_logical_channel_manager.h" using namespace srsran; -ue_drx_controller::ue_drx_controller(const cell_configuration& cell_cfg_common_, +ue_drx_controller::ue_drx_controller(subcarrier_spacing scs_common_, + std::chrono::milliseconds conres_timer_, const std::optional& drx_cfg_, const ul_logical_channel_manager& ul_lc_mng_, slot_point ul_ccch_slot_rx_) : - cell_cfg_common(cell_cfg_common_), drx_cfg(drx_cfg_), ul_lc_mng(ul_lc_mng_), ul_ccch_slot_rx(ul_ccch_slot_rx_) + scs_common(scs_common_), + conres_timer(conres_timer_), + drx_cfg(drx_cfg_), + ul_lc_mng(ul_lc_mng_), + ul_ccch_slot_rx(ul_ccch_slot_rx_) { if (drx_cfg.has_value()) { - const subcarrier_spacing scs = cell_cfg_common.dl_cfg_common.init_dl_bwp.generic_params.scs; - const unsigned nof_slots_per_sf = get_nof_slots_per_subframe(scs); + const unsigned nof_slots_per_sf = get_nof_slots_per_subframe(scs_common); active_window_period = drx_cfg.value().long_cycle.count() * nof_slots_per_sf; unsigned win_start = drx_cfg.value().long_start_offset.count() * nof_slots_per_sf; @@ -94,9 +97,7 @@ void ue_drx_controller::on_con_res_start() return; } - const subcarrier_spacing scs = cell_cfg_common.dl_cfg_common.init_dl_bwp.generic_params.scs; - const unsigned conres_slots = cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common->ra_con_res_timer.count() * - get_nof_slots_per_subframe(scs); + const unsigned conres_slots = conres_timer.count() * get_nof_slots_per_subframe(scs_common); slot_point new_time_end = ul_ccch_slot_rx + conres_slots; diff --git a/lib/scheduler/ue_context/ue_drx_controller.h b/lib/scheduler/ue_context/ue_drx_controller.h index 444a185445..e88b8693d6 100644 --- a/lib/scheduler/ue_context/ue_drx_controller.h +++ b/lib/scheduler/ue_context/ue_drx_controller.h @@ -24,8 +24,9 @@ class ul_logical_channel_manager; class ue_drx_controller { public: - ue_drx_controller(const cell_configuration& cell_cfg_common_, - const std::optional& drx_cfg_, + ue_drx_controller(const subcarrier_spacing scs_common, + std::chrono::milliseconds conres_timer, + const std::optional& drx_cfg, const ul_logical_channel_manager& ul_lc_mng, slot_point ul_ccch_slot_rx); @@ -45,7 +46,8 @@ class ue_drx_controller /// Whether the UE is within DRX active time. bool is_active_time(slot_point dl_slot) const; - const cell_configuration& cell_cfg_common; + const subcarrier_spacing scs_common; + std::chrono::milliseconds conres_timer; const std::optional& drx_cfg; const ul_logical_channel_manager& ul_lc_mng; slot_point ul_ccch_slot_rx; diff --git a/tests/unittests/scheduler/CMakeLists.txt b/tests/unittests/scheduler/CMakeLists.txt index 21b48cefa7..fec82ca021 100644 --- a/tests/unittests/scheduler/CMakeLists.txt +++ b/tests/unittests/scheduler/CMakeLists.txt @@ -14,6 +14,7 @@ add_subdirectory(test_utils) add_subdirectory(support) add_subdirectory(cell) add_subdirectory(common_scheduling) +add_subdirectory(ue_context) add_subdirectory(ue_scheduling) add_subdirectory(uci_and_pucch) add_subdirectory(policy) diff --git a/tests/unittests/scheduler/ue_context/CMakeLists.txt b/tests/unittests/scheduler/ue_context/CMakeLists.txt new file mode 100644 index 0000000000..6aacab16a6 --- /dev/null +++ b/tests/unittests/scheduler/ue_context/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# Copyright 2021-2024 Software Radio Systems Limited +# +# By using this file, you agree to the terms and conditions set +# forth in the LICENSE file which can be found at the top level of +# the distribution. +# + +add_executable(sched_ue_context_test ue_drx_controller_test.cpp) +target_link_libraries(sched_ue_context_test + sched_ue_context + srsran_support + srslog + gtest + gtest_main) +add_test(sched_ue_context_test sched_ue_context_test) \ No newline at end of file diff --git a/tests/unittests/scheduler/ue_context/ue_drx_controller_test.cpp b/tests/unittests/scheduler/ue_context/ue_drx_controller_test.cpp new file mode 100644 index 0000000000..9fc0e081d0 --- /dev/null +++ b/tests/unittests/scheduler/ue_context/ue_drx_controller_test.cpp @@ -0,0 +1,81 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "lib/scheduler/ue_context/ue_drx_controller.h" +#include "lib/scheduler/ue_context/ul_logical_channel_manager.h" +#include "srsran/support/test_utils.h" +#include + +using namespace srsran; + +using msec = std::chrono::milliseconds; + +class base_ue_drx_controller_test +{ +protected: + base_ue_drx_controller_test(const std::optional& drx_cfg_, slot_point ul_ccch_slot_ = {}) : + drx_cfg(drx_cfg_), ul_ccch_slot(ul_ccch_slot_) + { + } + + void tick() + { + drx.slot_indication(next_slot); + ++next_slot; + } + + const subcarrier_spacing scs = subcarrier_spacing::kHz30; + std::optional drx_cfg; + ul_logical_channel_manager ul_lc_ch_mng; + slot_point ul_ccch_slot; + ue_drx_controller drx{scs, msec{64}, drx_cfg, ul_lc_ch_mng, ul_ccch_slot}; + + slot_point next_slot{to_numerology_value(scs), + test_rgen::uniform_int(0, 10240) * get_nof_slots_per_subframe(scs) - 1}; +}; + +class drx_disabled_ue_drx_controller_test : public base_ue_drx_controller_test, public testing::Test +{ +protected: + drx_disabled_ue_drx_controller_test() : base_ue_drx_controller_test(std::nullopt) {} +}; + +TEST_F(drx_disabled_ue_drx_controller_test, when_no_drx_config_provided_pdcch_is_always_available) +{ + const unsigned NOF_TESTS = 16; + for (unsigned i = 0; i != NOF_TESTS; ++i) { + ASSERT_TRUE(drx.is_pdcch_enabled(next_slot)); + tick(); + } +} + +class ue_drx_controller_test : public base_ue_drx_controller_test, public testing::Test +{ +protected: + ue_drx_controller_test() : base_ue_drx_controller_test(drx_config{msec{80}, msec{10}, msec{20}, msec{10}}) {} + + const unsigned period_slots = drx_cfg->long_cycle.count() * get_nof_slots_per_subframe(scs); + const unsigned offset_slot = drx_cfg->long_start_offset.count() * get_nof_slots_per_subframe(scs); + const unsigned on_dur_slots = drx_cfg->on_duration_timer.count() * get_nof_slots_per_subframe(scs); +}; + +TEST_F(ue_drx_controller_test, when_drx_config_provided_slot_offset_and_on_duration_are_respected) +{ + for (unsigned i = 0; i != period_slots; ++i) { + bool enabled = drx.is_pdcch_enabled(next_slot); + + const unsigned slot_mod = next_slot.to_uint() % period_slots; + if (slot_mod >= offset_slot and slot_mod < (offset_slot + on_dur_slots)) { + ASSERT_TRUE(enabled); + } else { + ASSERT_FALSE(enabled); + } + } +} diff --git a/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp index cd27b3c1d0..a3fefbe6e3 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp @@ -82,7 +82,11 @@ class ue_cell_tester : public ::testing::Test ue_cell_configuration ue_cc_cfg; cell_harq_manager cell_harqs{1, MAX_NOF_HARQS}; ul_logical_channel_manager ul_lc_ch_mng; - ue_drx_controller drx_controller{cell_cfg, std::nullopt, ul_lc_ch_mng, {}}; + ue_drx_controller drx_controller{cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.scs, + cell_cfg.ul_cfg_common.init_ul_bwp.rach_cfg_common->ra_con_res_timer, + std::nullopt, + ul_lc_ch_mng, + {}}; }; TEST_F(ue_cell_tester, when_dl_nof_prb_allocated_increases_estimated_dl_rate_increases) From 5121af05872903fe1da506dd873af27f98267fe6 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 8 Nov 2024 19:04:41 +0100 Subject: [PATCH 23/26] sched: drx controller unit test --- .../ue_context/ue_drx_controller_test.cpp | 110 +++++++++++++++--- 1 file changed, 92 insertions(+), 18 deletions(-) diff --git a/tests/unittests/scheduler/ue_context/ue_drx_controller_test.cpp b/tests/unittests/scheduler/ue_context/ue_drx_controller_test.cpp index 9fc0e081d0..7b09bf7e50 100644 --- a/tests/unittests/scheduler/ue_context/ue_drx_controller_test.cpp +++ b/tests/unittests/scheduler/ue_context/ue_drx_controller_test.cpp @@ -20,25 +20,25 @@ using msec = std::chrono::milliseconds; class base_ue_drx_controller_test { protected: - base_ue_drx_controller_test(const std::optional& drx_cfg_, slot_point ul_ccch_slot_ = {}) : - drx_cfg(drx_cfg_), ul_ccch_slot(ul_ccch_slot_) - { - } + base_ue_drx_controller_test(const std::optional& drx_cfg_) : drx_cfg(drx_cfg_) {} void tick() { drx.slot_indication(next_slot); + cur_slot = next_slot; ++next_slot; } - const subcarrier_spacing scs = subcarrier_spacing::kHz30; - std::optional drx_cfg; - ul_logical_channel_manager ul_lc_ch_mng; - slot_point ul_ccch_slot; - ue_drx_controller drx{scs, msec{64}, drx_cfg, ul_lc_ch_mng, ul_ccch_slot}; + const subcarrier_spacing scs = subcarrier_spacing::kHz30; + const std::chrono::milliseconds conres_timer = msec{64}; + std::optional drx_cfg; + ul_logical_channel_manager ul_lc_ch_mng; + slot_point ul_ccch_slot{to_numerology_value(scs), 0}; + ue_drx_controller drx{scs, conres_timer, drx_cfg, ul_lc_ch_mng, ul_ccch_slot}; slot_point next_slot{to_numerology_value(scs), test_rgen::uniform_int(0, 10240) * get_nof_slots_per_subframe(scs) - 1}; + slot_point cur_slot; }; class drx_disabled_ue_drx_controller_test : public base_ue_drx_controller_test, public testing::Test @@ -51,8 +51,8 @@ TEST_F(drx_disabled_ue_drx_controller_test, when_no_drx_config_provided_pdcch_is { const unsigned NOF_TESTS = 16; for (unsigned i = 0; i != NOF_TESTS; ++i) { - ASSERT_TRUE(drx.is_pdcch_enabled(next_slot)); tick(); + ASSERT_TRUE(drx.is_pdcch_enabled(cur_slot)); } } @@ -61,21 +61,95 @@ class ue_drx_controller_test : public base_ue_drx_controller_test, public testin protected: ue_drx_controller_test() : base_ue_drx_controller_test(drx_config{msec{80}, msec{10}, msec{20}, msec{10}}) {} - const unsigned period_slots = drx_cfg->long_cycle.count() * get_nof_slots_per_subframe(scs); - const unsigned offset_slot = drx_cfg->long_start_offset.count() * get_nof_slots_per_subframe(scs); - const unsigned on_dur_slots = drx_cfg->on_duration_timer.count() * get_nof_slots_per_subframe(scs); + const unsigned period_slots = drx_cfg->long_cycle.count() * get_nof_slots_per_subframe(scs); + const unsigned offset_slot = drx_cfg->long_start_offset.count() * get_nof_slots_per_subframe(scs); + const unsigned on_dur_slots = drx_cfg->on_duration_timer.count() * get_nof_slots_per_subframe(scs); + const unsigned inactivity_slots = drx_cfg->inactivity_timer.count() * get_nof_slots_per_subframe(scs); }; TEST_F(ue_drx_controller_test, when_drx_config_provided_slot_offset_and_on_duration_are_respected) { for (unsigned i = 0; i != period_slots; ++i) { - bool enabled = drx.is_pdcch_enabled(next_slot); + tick(); - const unsigned slot_mod = next_slot.to_uint() % period_slots; - if (slot_mod >= offset_slot and slot_mod < (offset_slot + on_dur_slots)) { - ASSERT_TRUE(enabled); - } else { + const unsigned slot_mod = cur_slot.to_uint() % period_slots; + bool enabled = drx.is_pdcch_enabled(cur_slot); + bool in_active_window = slot_mod >= offset_slot and slot_mod < (offset_slot + on_dur_slots); + + ASSERT_EQ(enabled, in_active_window); + } +} + +TEST_F(ue_drx_controller_test, when_pdcch_sent_then_on_duration_extended_by_inactivity_timer) +{ + next_slot = slot_point{to_numerology_value(scs), 0}; + + const unsigned pdcch_idx = test_rgen::uniform_int(offset_slot + 1, offset_slot + on_dur_slots - 1); + const unsigned active_end = std::max(pdcch_idx + inactivity_slots, offset_slot + on_dur_slots); + + for (unsigned i = 0; i != period_slots; ++i) { + tick(); + + if (i == pdcch_idx) { + drx.on_new_pdcch_alloc(cur_slot); + } + + bool enabled = drx.is_pdcch_enabled(cur_slot); + if (i < offset_slot) { ASSERT_FALSE(enabled); + } else if (i < active_end) { + ASSERT_TRUE(enabled) << fmt::format( + "Failed active window detection at slot_mod={}, window=[{},{})", i, offset_slot, active_end); + } else { + ASSERT_FALSE(enabled) << fmt::format( + "Failed inactive window detection at slot_mod={}, window=[{},{})", i, offset_slot, active_end); } } } + +TEST_F(ue_drx_controller_test, when_sr_is_pending_then_drx_is_in_active_time) +{ + ul_lc_ch_mng.handle_sr_indication(); + + for (unsigned i = 0; i != period_slots; ++i) { + tick(); + + ASSERT_TRUE(drx.is_pdcch_enabled(cur_slot)); + } + + ul_lc_ch_mng.reset_sr_indication(); + + for (unsigned i = 0; i != period_slots; ++i) { + tick(); + + const unsigned slot_mod = cur_slot.to_uint() % period_slots; + bool enabled = drx.is_pdcch_enabled(cur_slot); + bool in_active_window = slot_mod >= offset_slot and slot_mod < (offset_slot + on_dur_slots); + + ASSERT_EQ(enabled, in_active_window); + } +} + +TEST_F(ue_drx_controller_test, when_conres_timer_is_running_then_drx_is_active) +{ + next_slot = slot_point{to_numerology_value(scs), 0}; + + const unsigned con_res_timer_slots = conres_timer.count() * get_nof_slots_per_subframe(scs); + + drx.on_con_res_start(); + + for (unsigned i = 0; i != con_res_timer_slots; ++i) { + tick(); + ASSERT_TRUE(drx.is_pdcch_enabled(cur_slot)) << "DRX should be active while ra-ConResTimer is running"; + } + + for (unsigned i = 0; i != period_slots; ++i) { + tick(); + + const unsigned slot_mod = cur_slot.to_uint() % period_slots; + bool enabled = drx.is_pdcch_enabled(cur_slot); + bool in_active_window = slot_mod >= offset_slot and slot_mod < (offset_slot + on_dur_slots); + + ASSERT_EQ(enabled, in_active_window); + } +} From dab768b181e431a3bd43fb813ac38c018a706fd1 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 11 Nov 2024 14:54:38 +0100 Subject: [PATCH 24/26] sched: add comments to DRX controller --- include/srsran/ran/drx_config.h | 2 +- lib/scheduler/config/ue_configuration.cpp | 7 +++---- lib/scheduler/ue_context/ue_drx_controller.h | 10 ++++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/srsran/ran/drx_config.h b/include/srsran/ran/drx_config.h index 03c68ed056..f739d37a68 100644 --- a/include/srsran/ran/drx_config.h +++ b/include/srsran/ran/drx_config.h @@ -19,7 +19,7 @@ namespace srsran { struct drx_config { /// Period of the DRX cycle. See "drx-LongCycleStartOffset" in TS 38.331. std::chrono::milliseconds long_cycle; - /// Start Offset of the DRX long cycle.. See "drx-LongCycleStartOffset" in TS 38.331. Values {0,...,long_cycle - 1} + /// Start Offset of the DRX long cycle. See "drx-LongCycleStartOffset" in TS 38.331. Values {0,...,long_cycle - 1}. std::chrono::milliseconds long_start_offset; /// Duration at the beginning of a DRX cycle. std::chrono::milliseconds on_duration_timer; diff --git a/lib/scheduler/config/ue_configuration.cpp b/lib/scheduler/config/ue_configuration.cpp index c57976576e..2ca279db6d 100644 --- a/lib/scheduler/config/ue_configuration.cpp +++ b/lib/scheduler/config/ue_configuration.cpp @@ -839,10 +839,9 @@ void ue_configuration::update(const cell_common_configuration_list& common_cells if (not du_cells.contains(cell_index)) { // New Cell. - du_cells.emplace( - cell_index, - std::make_unique( - crnti, *common_cells[cell_index], ded_cell.serv_cell_cfg, ded_cell.meas_gap_cfg, e > 1)); + du_cells.emplace(cell_index, + std::make_unique( + crnti, *common_cells[cell_index], ded_cell.serv_cell_cfg, ded_cell.meas_gap_cfg, e > 1)); } else { // Reconfiguration of existing cell. du_cells[cell_index]->reconfigure(ded_cell.serv_cell_cfg, ded_cell.meas_gap_cfg); diff --git a/lib/scheduler/ue_context/ue_drx_controller.h b/lib/scheduler/ue_context/ue_drx_controller.h index e88b8693d6..f32b8b4615 100644 --- a/lib/scheduler/ue_context/ue_drx_controller.h +++ b/lib/scheduler/ue_context/ue_drx_controller.h @@ -51,12 +51,14 @@ class ue_drx_controller const std::optional& drx_cfg; const ul_logical_channel_manager& ul_lc_mng; slot_point ul_ccch_slot_rx; - unsigned active_window_period; - interval active_window; - unsigned inactivity_dur; + + // Converted config parameters from milliseconds to slots. + unsigned active_window_period; + interval active_window; + unsigned inactivity_dur; // End slot for the active window. When invalid, the UE is not in active window. slot_point active_time_end; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran From 5f0a53843108dbc633e74267b3e7d2ba722609d8 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 11 Nov 2024 16:11:32 +0100 Subject: [PATCH 25/26] sched: make UL-CCCH slot_rx an optional --- include/srsran/du/du_high/du_manager/du_manager.h | 4 ---- include/srsran/mac/mac_ue_configurator.h | 2 +- include/srsran/scheduler/scheduler_configurator.h | 2 +- .../du_manager/procedures/ue_creation_procedure.h | 6 +++--- lib/scheduler/ue_context/ue.cpp | 3 ++- lib/scheduler/ue_context/ue.h | 8 ++++---- lib/scheduler/ue_context/ue_drx_controller.cpp | 12 +++++++++--- lib/scheduler/ue_context/ue_drx_controller.h | 9 ++++++--- .../scheduler/ue_context/ue_drx_controller_test.cpp | 3 ++- .../scheduler/ue_scheduling/ue_cell_test.cpp | 4 +++- 10 files changed, 31 insertions(+), 22 deletions(-) diff --git a/include/srsran/du/du_high/du_manager/du_manager.h b/include/srsran/du/du_high/du_manager/du_manager.h index 85e10c85f6..360d9de2e9 100644 --- a/include/srsran/du/du_high/du_manager/du_manager.h +++ b/include/srsran/du/du_high/du_manager/du_manager.h @@ -1,14 +1,10 @@ #pragma once -#include "srsran/adt/byte_buffer.h" #include "srsran/du/du_high/du_manager/du_configurator.h" #include "srsran/f1ap/du/f1ap_du.h" #include "srsran/ran/du_types.h" -#include "srsran/ran/logical_channel/lcid.h" -#include "srsran/ran/rnti.h" #include "srsran/support/async/async_task.h" -#include namespace srsran { diff --git a/include/srsran/mac/mac_ue_configurator.h b/include/srsran/mac/mac_ue_configurator.h index 4683775a17..bbda542254 100644 --- a/include/srsran/mac/mac_ue_configurator.h +++ b/include/srsran/mac/mac_ue_configurator.h @@ -66,7 +66,7 @@ struct mac_ue_create_request { physical_cell_group_config phy_cell_group_cfg; bool initial_fallback = true; const byte_buffer* ul_ccch_msg = nullptr; - slot_point ul_ccch_slot_rx; + std::optional ul_ccch_slot_rx; // Scheduler-only params. sched_ue_config_request sched_cfg; diff --git a/include/srsran/scheduler/scheduler_configurator.h b/include/srsran/scheduler/scheduler_configurator.h index b15c18c50e..c74da852ef 100644 --- a/include/srsran/scheduler/scheduler_configurator.h +++ b/include/srsran/scheduler/scheduler_configurator.h @@ -154,7 +154,7 @@ struct sched_ue_creation_request_message { /// Whether the UE starts in fallback mode, i.e. without using its dedicated configuration. bool starts_in_fallback; /// Slot at which UL-CCCH message was received, in case of RA-based UE creation. Invalid, otherwise. - slot_point ul_ccch_slot_rx; + std::optional ul_ccch_slot_rx; /// Configuration to be applied to the new UE. sched_ue_config_request cfg; /// Time Alignment Group configuration. diff --git a/lib/du/du_high/du_manager/procedures/ue_creation_procedure.h b/lib/du/du_high/du_manager/procedures/ue_creation_procedure.h index a2d38581c2..1267d9f087 100644 --- a/lib/du/du_high/du_manager/procedures/ue_creation_procedure.h +++ b/lib/du/du_high/du_manager/procedures/ue_creation_procedure.h @@ -29,9 +29,9 @@ struct du_ue_creation_request { rnti_t tc_rnti; /// \brief UL-CCCH message received from the UE in Msg3. Empty if the UE is created by upper layers. byte_buffer ul_ccch_msg; - /// \brief Slot at which the UL-CCCH message was received in the PUSCH. Invalid slot if the UE is created by upper - /// layers. - slot_point slot_rx; + /// \brief If present, it represents the slot at which the UL-CCCH message was received in the PUSCH. Absent, when + /// the UE is created by command from upper layers. + std::optional slot_rx; }; /// \brief Handles the creation of a UE and respective bearers in the DU UE manager, MAC, F1. diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index f53b33225f..380500d244 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -28,7 +28,8 @@ ue::ue(const ue_creation_command& cmd) : cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common->ra_con_res_timer, cmd.cfg.drx_cfg(), ul_lc_ch_mgr, - cmd.ul_ccch_slot_rx) + cmd.ul_ccch_slot_rx, + logger) { // Apply configuration. handle_reconfiguration_request(ue_reconf_command{cmd.cfg}); diff --git a/lib/scheduler/ue_context/ue.h b/lib/scheduler/ue_context/ue.h index 83053e4244..d87d3f6c3b 100644 --- a/lib/scheduler/ue_context/ue.h +++ b/lib/scheduler/ue_context/ue.h @@ -22,10 +22,10 @@ namespace srsran { /// Parameters used to create a UE. struct ue_creation_command { - const ue_configuration& cfg; - bool starts_in_fallback; - cell_harq_manager& pcell_harq_pool; - slot_point ul_ccch_slot_rx; + const ue_configuration& cfg; + bool starts_in_fallback; + cell_harq_manager& pcell_harq_pool; + std::optional ul_ccch_slot_rx; }; /// Parameters used to reconfigure a UE. diff --git a/lib/scheduler/ue_context/ue_drx_controller.cpp b/lib/scheduler/ue_context/ue_drx_controller.cpp index df81ae01ad..0b75d03e07 100644 --- a/lib/scheduler/ue_context/ue_drx_controller.cpp +++ b/lib/scheduler/ue_context/ue_drx_controller.cpp @@ -17,12 +17,14 @@ ue_drx_controller::ue_drx_controller(subcarrier_spacing scs_commo std::chrono::milliseconds conres_timer_, const std::optional& drx_cfg_, const ul_logical_channel_manager& ul_lc_mng_, - slot_point ul_ccch_slot_rx_) : + std::optional ul_ccch_slot_rx_, + srslog::basic_logger& logger_) : scs_common(scs_common_), conres_timer(conres_timer_), drx_cfg(drx_cfg_), ul_lc_mng(ul_lc_mng_), - ul_ccch_slot_rx(ul_ccch_slot_rx_) + ul_ccch_slot_rx(ul_ccch_slot_rx_), + logger(logger_) { if (drx_cfg.has_value()) { const unsigned nof_slots_per_sf = get_nof_slots_per_subframe(scs_common); @@ -96,10 +98,14 @@ void ue_drx_controller::on_con_res_start() if (not drx_cfg.has_value()) { return; } + if (not ul_ccch_slot_rx.has_value() or not ul_ccch_slot_rx.value().valid()) { + logger.error("Setting conRes timer but slot of UL-CCCH was not registered"); + return; + } const unsigned conres_slots = conres_timer.count() * get_nof_slots_per_subframe(scs_common); - slot_point new_time_end = ul_ccch_slot_rx + conres_slots; + slot_point new_time_end = ul_ccch_slot_rx.value() + conres_slots; if (not active_time_end.valid() or active_time_end < new_time_end) { // "the Active Time includes the time while [...] ra-ContentionResolutionTimer [...] is running." diff --git a/lib/scheduler/ue_context/ue_drx_controller.h b/lib/scheduler/ue_context/ue_drx_controller.h index f32b8b4615..cb6311278e 100644 --- a/lib/scheduler/ue_context/ue_drx_controller.h +++ b/lib/scheduler/ue_context/ue_drx_controller.h @@ -12,6 +12,7 @@ #include "srsran/ran/drx_config.h" #include "srsran/ran/slot_point.h" +#include "srsran/srslog/logger.h" #include namespace srsran { @@ -24,11 +25,12 @@ class ul_logical_channel_manager; class ue_drx_controller { public: - ue_drx_controller(const subcarrier_spacing scs_common, + ue_drx_controller(subcarrier_spacing scs_common, std::chrono::milliseconds conres_timer, const std::optional& drx_cfg, const ul_logical_channel_manager& ul_lc_mng, - slot_point ul_ccch_slot_rx); + std::optional ul_ccch_slot_rx, + srslog::basic_logger& logger); /// Update DRX controller state. void slot_indication(slot_point dl_slot); @@ -50,7 +52,8 @@ class ue_drx_controller std::chrono::milliseconds conres_timer; const std::optional& drx_cfg; const ul_logical_channel_manager& ul_lc_mng; - slot_point ul_ccch_slot_rx; + std::optional ul_ccch_slot_rx; + srslog::basic_logger& logger; // Converted config parameters from milliseconds to slots. unsigned active_window_period; diff --git a/tests/unittests/scheduler/ue_context/ue_drx_controller_test.cpp b/tests/unittests/scheduler/ue_context/ue_drx_controller_test.cpp index 7b09bf7e50..d59e6b7703 100644 --- a/tests/unittests/scheduler/ue_context/ue_drx_controller_test.cpp +++ b/tests/unittests/scheduler/ue_context/ue_drx_controller_test.cpp @@ -34,7 +34,8 @@ class base_ue_drx_controller_test std::optional drx_cfg; ul_logical_channel_manager ul_lc_ch_mng; slot_point ul_ccch_slot{to_numerology_value(scs), 0}; - ue_drx_controller drx{scs, conres_timer, drx_cfg, ul_lc_ch_mng, ul_ccch_slot}; + srslog::basic_logger& logger = srslog::fetch_basic_logger("SCHED"); + ue_drx_controller drx{scs, conres_timer, drx_cfg, ul_lc_ch_mng, ul_ccch_slot, logger}; slot_point next_slot{to_numerology_value(scs), test_rgen::uniform_int(0, 10240) * get_nof_slots_per_subframe(scs) - 1}; diff --git a/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp index a3fefbe6e3..80d0219bac 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_cell_test.cpp @@ -82,11 +82,13 @@ class ue_cell_tester : public ::testing::Test ue_cell_configuration ue_cc_cfg; cell_harq_manager cell_harqs{1, MAX_NOF_HARQS}; ul_logical_channel_manager ul_lc_ch_mng; + srslog::basic_logger& logger = srslog::fetch_basic_logger("SCHED"); ue_drx_controller drx_controller{cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.scs, cell_cfg.ul_cfg_common.init_ul_bwp.rach_cfg_common->ra_con_res_timer, std::nullopt, ul_lc_ch_mng, - {}}; + {}, + logger}; }; TEST_F(ue_cell_tester, when_dl_nof_prb_allocated_increases_estimated_dl_rate_increases) From a77e99fd45ffd22dd2bf16783cc4a72b1f68dd44 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 11 Nov 2024 18:03:40 +0100 Subject: [PATCH 26/26] sched: fix data race in access to drx config --- lib/scheduler/ue_context/ue_drx_controller.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scheduler/ue_context/ue_drx_controller.h b/lib/scheduler/ue_context/ue_drx_controller.h index cb6311278e..8803d47bc6 100644 --- a/lib/scheduler/ue_context/ue_drx_controller.h +++ b/lib/scheduler/ue_context/ue_drx_controller.h @@ -50,7 +50,7 @@ class ue_drx_controller const subcarrier_spacing scs_common; std::chrono::milliseconds conres_timer; - const std::optional& drx_cfg; + const std::optional drx_cfg; const ul_logical_channel_manager& ul_lc_mng; std::optional ul_ccch_slot_rx; srslog::basic_logger& logger;