Skip to content

Commit 8e2001a

Browse files
xavierarteagacodebot
authored andcommitted
phy: review channel equalizer abnormal cases
1 parent 011905c commit 8e2001a

File tree

5 files changed

+77
-22
lines changed

5 files changed

+77
-22
lines changed

include/srsran/phy/support/re_buffer.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -278,13 +278,15 @@ class static_re_buffer : public re_buffer_reader<T>, public re_buffer_writer<T>
278278
/// \ref set_slice method.
279279
///
280280
/// \tparam T Resource element type.
281-
template <typename T = cf_t>
281+
template <unsigned MaxNofSlices, typename T = cf_t>
282282
class modular_re_buffer_reader : public re_buffer_reader<T>
283283
{
284284
public:
285-
/// \brief Constructs a modular resource element buffer for a given maximum number of slices and resource elements.
286-
/// \param[in] max_nof_slices Maximum number of slices.
287-
modular_re_buffer_reader(unsigned max_nof_slices) : nof_slices(0), nof_re(0), data(max_nof_slices) {}
285+
/// Constructs a modular resource element buffer.
286+
modular_re_buffer_reader() : nof_slices(0), nof_re(0) {}
287+
288+
/// Constructs a modular resource element buffer for a given number of slices and resource elements.
289+
modular_re_buffer_reader(unsigned nof_slices_, unsigned nof_re_) { resize(nof_slices_, nof_re_); }
288290

289291
/// \brief Resizes the buffer view to a desired number of RE and slices.
290292
/// \param[in] nof_slices Number of slices.
@@ -340,7 +342,7 @@ class modular_re_buffer_reader : public re_buffer_reader<T>
340342
unsigned nof_re;
341343

342344
/// Internal data storage.
343-
std::vector<span<const T>> data;
345+
std::array<span<const T>, MaxNofSlices> data;
344346
};
345347

346348
/// \brief Implements a modular resource element buffer writer.

include/srsran/phy/upper/equalization/modular_ch_est_list.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
namespace srsran {
1717

1818
/// Implements the list of channel estimates with views to each of the channels.
19+
template <unsigned MaxNofElements>
1920
class modular_ch_est_list : public channel_equalizer::ch_est_list
2021
{
2122
public:
@@ -25,6 +26,12 @@ class modular_ch_est_list : public channel_equalizer::ch_est_list
2526
modular_ch_est_list(unsigned max_nof_rx_ports_, unsigned max_nof_layers_) :
2627
max_nof_rx_ports(max_nof_rx_ports_), max_nof_layers(max_nof_layers_), data({max_nof_rx_ports, max_nof_layers})
2728
{
29+
srsran_assert(max_nof_rx_ports * max_nof_layers <= MaxNofElements,
30+
"The maximum number of layers (i.e., {}) times the maximum number of ports (i.e., {}) exceeds the "
31+
"maximum number of elements (i.e., {})",
32+
max_nof_layers,
33+
max_nof_rx_ports,
34+
MaxNofElements);
2835
}
2936

3037
/// \brief Sets the contents of a channel.
@@ -97,7 +104,7 @@ class modular_ch_est_list : public channel_equalizer::ch_est_list
97104
/// Maximum number of layers.
98105
unsigned max_nof_layers;
99106
/// Data storage as a tensor of views for each channel.
100-
dynamic_tensor<std::underlying_type_t<ch_dims>(ch_dims::nof_dims), span<const cbf16_t>, ch_dims> data;
107+
static_tensor<std::underlying_type_t<ch_dims>(ch_dims::nof_dims), span<const cbf16_t>, MaxNofElements, ch_dims> data;
101108
};
102109

103110
} // namespace srsran

lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ class pusch_demodulator_impl : public pusch_demodulator
4646
evm_calc(std::move(evm_calc_)),
4747
descrambler(std::move(descrambler_)),
4848
ch_re_copy(MAX_PORTS, max_nof_rb * NRE),
49-
ch_re_view(pusch_constants::MAX_NOF_RX_PORTS),
5049
temp_eq_re(max_nof_rb * NRE * pusch_constants::MAX_NOF_LAYERS),
5150
temp_eq_noise_vars(max_nof_rb * NRE * pusch_constants::MAX_NOF_LAYERS),
5251
ch_estimates_copy(max_nof_rb * NRE, pusch_constants::MAX_NOF_RX_PORTS, pusch_constants::MAX_NOF_LAYERS),
@@ -215,15 +214,15 @@ class pusch_demodulator_impl : public pusch_demodulator
215214
/// Copy buffer used to transfer channel modulation symbols from the resource grid to the equalizer.
216215
dynamic_re_buffer<cbf16_t> ch_re_copy;
217216
/// View buffer used to transfer channel modulation symbols from the resource grid to the equalizer.
218-
modular_re_buffer_reader<cbf16_t> ch_re_view;
217+
modular_re_buffer_reader<MAX_PORTS, cbf16_t> ch_re_view;
219218
/// Buffer used to store channel modulation resource elements at the equalizer output.
220219
std::vector<cf_t> temp_eq_re;
221220
/// Buffer used to transfer symbol noise variances at the equalizer output.
222221
std::vector<float> temp_eq_noise_vars;
223222
/// Copy buffer used to transfer channel estimation coefficients from the channel estimate to the equalizer.
224223
dynamic_ch_est_list ch_estimates_copy;
225224
/// View buffer used to transfer channel estimation coefficients from the channel estimate to the equalizer.
226-
modular_ch_est_list ch_estimates_view;
225+
modular_ch_est_list<pusch_constants::MAX_NOF_RX_PORTS * pusch_constants::MAX_NOF_LAYERS> ch_estimates_view;
227226
/// Buffer used to transfer noise variance estimates from the channel estimate to the equalizer.
228227
std::array<float, MAX_PORTS> noise_var_estimates;
229228

lib/phy/upper/equalization/channel_equalizer_generic_impl.cpp

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "equalize_zf_1xn.h"
1717
#include "equalize_zf_2xn.h"
1818
#include "srsran/adt/interval.h"
19+
#include "srsran/phy/support/re_buffer.h"
20+
#include "srsran/phy/upper/equalization/modular_ch_est_list.h"
1921

2022
using namespace srsran;
2123

@@ -116,6 +118,61 @@ void equalize_zf_single_tx_layer<1>(unsigned /**/,
116118
equalize_zf_1xn<1>(eq_symbols, eq_noise_vars, ch_symbols, ch_estimates, noise_var, tx_scaling);
117119
}
118120

121+
template <unsigned NOF_PORTS>
122+
void equalize_zf_single_tx_layer_reduction(unsigned nof_ports,
123+
span<cf_t> eq_symbols,
124+
span<float> eq_noise_vars,
125+
const re_buffer_reader<cbf16_t>& ch_symbols,
126+
const channel_equalizer::ch_est_list& ch_estimates,
127+
span<const float> noise_var,
128+
float tx_scaling)
129+
{
130+
// Function for checking if a noise variance is valid.
131+
const auto func_valid_noise_var = [](float nvar) {
132+
return (nvar > 0) && (nvar < std::numeric_limits<float>::infinity());
133+
};
134+
135+
// Count the number of valid noise variances.
136+
unsigned nof_valid_noise_var = std::count_if(noise_var.begin(), noise_var.end(), func_valid_noise_var);
137+
138+
// No valid noise variances, fill output with invalid data.
139+
if (nof_valid_noise_var == 0) {
140+
srsvec::zero(eq_symbols);
141+
srsvec::fill(eq_noise_vars, std::numeric_limits<float>::infinity());
142+
return;
143+
}
144+
145+
// Exclude the ports that are invalid.
146+
if (nof_valid_noise_var != nof_ports) {
147+
// Reduce ports.
148+
static_vector<float, NOF_PORTS> reduced_noise_var(nof_valid_noise_var);
149+
modular_re_buffer_reader<NOF_PORTS, cbf16_t> reduced_ch_symbols(nof_ports, ch_symbols.get_nof_re());
150+
modular_ch_est_list<NOF_PORTS> reduced_ch_estimates(nof_ports, ch_symbols.get_nof_re());
151+
for (unsigned i_port = 0, i_reduced_port = 0; i_port != nof_ports; ++i_port) {
152+
if (func_valid_noise_var(noise_var[i_port])) {
153+
reduced_noise_var[i_reduced_port] = noise_var[i_port];
154+
reduced_ch_symbols.set_slice(i_reduced_port, ch_symbols.get_slice(i_port));
155+
reduced_ch_estimates.set_channel(ch_estimates.get_channel(i_port, 0), i_reduced_port, 0);
156+
++i_reduced_port;
157+
}
158+
}
159+
160+
// Equalize. The number of ports must be at least one less than before.
161+
equalize_zf_single_tx_layer<NOF_PORTS - 1>(nof_valid_noise_var,
162+
eq_symbols,
163+
eq_noise_vars,
164+
reduced_ch_symbols,
165+
reduced_ch_estimates,
166+
reduced_noise_var,
167+
tx_scaling);
168+
return;
169+
}
170+
171+
// Perform equalization for all ports.
172+
equalize_zf_single_tx_layer<NOF_PORTS>(
173+
nof_valid_noise_var, eq_symbols, eq_noise_vars, ch_symbols, ch_estimates, noise_var, tx_scaling);
174+
}
175+
119176
/// Calls the equalizer function for receive spatial diversity with the appropriate number of receive ports.
120177
template <unsigned NOF_PORTS>
121178
void equalize_mmse_single_tx_layer(unsigned nof_ports,
@@ -173,7 +230,7 @@ void channel_equalizer_generic_impl::equalize(span<cf_t> e
173230
if (type == channel_equalizer_algorithm_type::zf) {
174231
// Single transmit layer and any number of receive ports.
175232
if (nof_tx_layers == 1) {
176-
equalize_zf_single_tx_layer<MAX_PORTS>(
233+
equalize_zf_single_tx_layer_reduction<MAX_PORTS>(
177234
nof_rx_ports, eq_symbols, eq_noise_vars, ch_symbols, ch_estimates, noise_var_estimates, tx_scaling);
178235
return;
179236
}

lib/phy/upper/equalization/equalize_zf_1xn.h

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,8 @@ void equalize_zf_1xn(span<cf_t> symbols_out,
7474
// Load noise variance in a SIMD register.
7575
simd_f_t port_noise_var_est = srsran_simd_f_set1(noise_var_est[i_port]);
7676

77-
// Detect abnormal computation parameters. This detects whether the channel estimate and the port noise variance
78-
// estimation are negative, NaN or infinite.
79-
simd_sel_t isnormal_mask = srsran_simd_f_max(ch_est_norm, zero);
80-
isnormal_mask = srsran_simd_sel_and(isnormal_mask, srsran_simd_f_max(infinity, ch_est_norm));
81-
isnormal_mask = srsran_simd_sel_and(isnormal_mask, srsran_simd_f_max(port_noise_var_est, zero));
82-
isnormal_mask = srsran_simd_sel_and(isnormal_mask, srsran_simd_f_max(infinity, port_noise_var_est));
77+
// Detect an abnormal computation parameter. This detects whether the channel estimate is NaN or infinite.
78+
simd_sel_t isnormal_mask = srsran_simd_f_max(infinity, ch_est_norm);
8379

8480
// Compute the channel square norm, by accumulating the channel square absolute values.
8581
ch_mod_sq = srsran_simd_f_add_sel(ch_mod_sq, ch_est_norm, isnormal_mask);
@@ -106,12 +102,6 @@ void equalize_zf_1xn(span<cf_t> symbols_out,
106102
// Calculate noise variances.
107103
simd_f_t vars_out = srsran_simd_f_mul(nvar_acc, srsran_simd_f_mul(d_pinv_rcp, d_pinv_rcp));
108104

109-
// Detect whenever the post-equalization noise variances are zero, negative or NaN.
110-
isnormal_mask = srsran_simd_sel_and(isnormal_mask, srsran_simd_f_max(vars_out, zero));
111-
112-
// Detect whenever the post-equalization noise variances are set to infinity.
113-
isnormal_mask = srsran_simd_sel_and(isnormal_mask, srsran_simd_f_max(infinity, vars_out));
114-
115105
// If abnormal calculation parameters are detected, the noise variances are set to infinity.
116106
srsran_simd_f_storeu(nvars_out.data() + i_re, srsran_simd_f_select(infinity, vars_out, isnormal_mask));
117107

0 commit comments

Comments
 (0)