Skip to content

Commit efcf424

Browse files
committed
phy: concurrent port channel estimator
This implementation of the port channel estimator provides access to a pool of channel estimators. This is the first step towards parallelizing the estimation across multiple antenna ports.
1 parent 19a54b7 commit efcf424

File tree

4 files changed

+121
-0
lines changed

4 files changed

+121
-0
lines changed

include/srsran/phy/upper/signal_processors/signal_processor_factories.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ class port_channel_estimator_factory
109109
std::shared_ptr<port_channel_estimator_factory>
110110
create_port_channel_estimator_factory_sw(std::shared_ptr<time_alignment_estimator_factory> ta_estimator_factory);
111111

112+
std::shared_ptr<port_channel_estimator_factory>
113+
create_port_channel_estimator_pool_factory(std::shared_ptr<port_channel_estimator_factory> ch_est_factory,
114+
unsigned nof_concurrent_threads);
115+
112116
class pss_processor_factory
113117
{
114118
public:
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
*
3+
* Copyright 2021-2025 Software Radio Systems Limited
4+
*
5+
* By using this file, you agree to the terms and conditions set
6+
* forth in the LICENSE file which can be found at the top level of
7+
* the distribution.
8+
*
9+
*/
10+
11+
#pragma once
12+
13+
#include "srsran/phy/upper/signal_processors/port_channel_estimator.h"
14+
#include "srsran/srslog/srslog.h"
15+
#include "srsran/support/memory_pool/bounded_object_pool.h"
16+
17+
namespace srsran {
18+
19+
/// Concurrent port channel estimator.
20+
class port_channel_estimator_pool : public port_channel_estimator
21+
{
22+
public:
23+
using estimator_pool = bounded_unique_object_pool<port_channel_estimator>;
24+
25+
/// Creates a concurrent channel estimator from a shared pool of estimators.
26+
explicit port_channel_estimator_pool(std::shared_ptr<estimator_pool> estimators_) :
27+
logger(srslog::fetch_basic_logger("PHY")), estimators(std::move(estimators_))
28+
{
29+
srsran_assert(estimators, "Invalid port channel estimator pool.");
30+
}
31+
32+
// See interface for documentation.
33+
void compute(channel_estimate& estimate,
34+
const resource_grid_reader& grid,
35+
unsigned port,
36+
const dmrs_symbol_list& pilots,
37+
const configuration& cfg) override
38+
{
39+
auto estimator = estimators->get();
40+
if (!estimator) {
41+
logger.error("Failed to retrieve a port channel estimator.");
42+
return;
43+
}
44+
45+
estimator->compute(estimate, grid, port, pilots, cfg);
46+
}
47+
48+
private:
49+
srslog::basic_logger& logger;
50+
// Pool of port channel estimators.
51+
std::shared_ptr<estimator_pool> estimators;
52+
};
53+
54+
} // namespace srsran

lib/phy/upper/signal_processors/signal_processor_factories.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "nzp_csi_rs_generator_impl.h"
1717
#include "nzp_csi_rs_generator_pool.h"
1818
#include "port_channel_estimator_average_impl.h"
19+
#include "port_channel_estimator_pool.h"
1920
#include "pss_processor_impl.h"
2021
#include "pucch/dmrs_pucch_estimator_format2.h"
2122
#include "pucch/dmrs_pucch_estimator_formats3_4.h"
@@ -25,6 +26,7 @@
2526
#include "srsran/phy/support/support_formatters.h"
2627
#include "srsran/phy/support/time_alignment_estimator/time_alignment_estimator_factories.h"
2728
#include "srsran/phy/upper/signal_processors/signal_processor_formatters.h"
29+
#include <map>
2830

2931
using namespace srsran;
3032

@@ -270,6 +272,56 @@ class port_channel_estimator_factory_sw : public port_channel_estimator_factory
270272
std::shared_ptr<time_alignment_estimator_factory> ta_estimator_factory;
271273
};
272274

275+
class port_channel_estimator_pool_factory : public port_channel_estimator_factory
276+
{
277+
public:
278+
port_channel_estimator_pool_factory(std::shared_ptr<port_channel_estimator_factory> factory_,
279+
unsigned nof_concurrent_threads_) :
280+
factory(std::move(factory_)), nof_concurrent_threads(nof_concurrent_threads_)
281+
{
282+
srsran_assert(factory, "Invalid port channel estimator factory.");
283+
srsran_assert(nof_concurrent_threads > 1, "Number of concurrent threads must be greater than one.");
284+
}
285+
286+
std::unique_ptr<port_channel_estimator>
287+
create(port_channel_estimator_fd_smoothing_strategy fd_smoothing_strategy,
288+
port_channel_estimator_td_interpolation_strategy td_interpolation_strategy,
289+
bool compensate_cfo) override
290+
{
291+
auto& this_estimator_pool = estimators[{fd_smoothing_strategy, td_interpolation_strategy, compensate_cfo}];
292+
if (!this_estimator_pool) {
293+
std::vector<std::unique_ptr<port_channel_estimator>> instances(nof_concurrent_threads);
294+
std::generate(instances.begin(),
295+
instances.end(),
296+
[this, fd_smoothing_strategy, td_interpolation_strategy, compensate_cfo]() {
297+
return factory->create(fd_smoothing_strategy, td_interpolation_strategy, compensate_cfo);
298+
});
299+
this_estimator_pool = std::make_shared<port_channel_estimator_pool::estimator_pool>(instances);
300+
}
301+
return std::make_unique<port_channel_estimator_pool>(this_estimator_pool);
302+
}
303+
304+
private:
305+
using estimator_config =
306+
std::tuple<port_channel_estimator_fd_smoothing_strategy, port_channel_estimator_td_interpolation_strategy, bool>;
307+
308+
struct config_hash {
309+
size_t operator()(const estimator_config& c) const noexcept
310+
{
311+
size_t h1 = std::hash<int>{}(static_cast<int>(std::get<0>(c)));
312+
size_t h2 = std::hash<int>{}(static_cast<int>(std::get<1>(c)));
313+
size_t h3 = std::hash<bool>{}(std::get<2>(c));
314+
315+
return (h1 ^ (h2 << 1) ^ (h3 << 2));
316+
}
317+
};
318+
319+
std::shared_ptr<port_channel_estimator_factory> factory;
320+
unsigned nof_concurrent_threads;
321+
std::unordered_map<estimator_config, std::shared_ptr<port_channel_estimator_pool::estimator_pool>, config_hash>
322+
estimators;
323+
};
324+
273325
class pss_processor_factory_sw : public pss_processor_factory
274326
{
275327
public:
@@ -349,6 +401,13 @@ srsran::create_port_channel_estimator_factory_sw(std::shared_ptr<time_alignment_
349401
return std::make_shared<port_channel_estimator_factory_sw>(std::move(ta_estimator_factory));
350402
}
351403

404+
std::shared_ptr<port_channel_estimator_factory>
405+
srsran::create_port_channel_estimator_pool_factory(std::shared_ptr<port_channel_estimator_factory> ch_est_factory,
406+
unsigned nof_concurrent_threads)
407+
{
408+
return std::make_shared<port_channel_estimator_pool_factory>(std::move(ch_est_factory), nof_concurrent_threads);
409+
}
410+
352411
std::shared_ptr<pss_processor_factory> srsran::create_pss_processor_factory_sw()
353412
{
354413
return std::make_shared<pss_processor_factory_sw>();

tests/unittests/phy/upper/signal_processors/port_channel_estimator_test.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ class ChannelEstFixture : public ::testing::TestWithParam<test_case_t>
6262
ASSERT_NE(ta_estimator_factory, nullptr) << "Cannot create TA estimator factory.";
6363

6464
ch_est_factory = create_port_channel_estimator_factory_sw(std::move(ta_estimator_factory));
65+
// The concurrent version of the port channel estimator is just a collection of channel estimators which are
66+
// called according to their availability. Using the concurrent estimator in the test ensures that
67+
// port_channel_estimator can be called from the pool, without broadening too much the scope of the test.
68+
ch_est_factory = create_port_channel_estimator_pool_factory(std::move(ch_est_factory), 2);
6569
ASSERT_NE(ch_est_factory, nullptr);
6670
}
6771
}

0 commit comments

Comments
 (0)