Skip to content

Commit 30e370e

Browse files
committed
ch estimator: improve noise estimation
After introducing CFO estimation and compensation, the noise estimation was failing.
1 parent 6521a3d commit 30e370e

File tree

1 file changed

+86
-36
lines changed

1 file changed

+86
-36
lines changed

lib/phy/upper/signal_processors/port_channel_estimator_average_impl.cpp

Lines changed: 86 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ static unsigned extract_layer_hop_rx_pilots(dmrs_symbol_list&
153153
/// \param[out] pilot_products Helper buffer for internal computations (same size as pilots_lse).
154154
/// \param[in] rx_pilots Received pilots.
155155
/// \param[in] pilots Transmitted pilots.
156+
/// \param[in] dmrs_mask Boolean mask identifying the OFDM symbols carrying DM-RS within the slot.
156157
/// \param[in] scs Subcarrier spacing.
157158
/// \param[in] cp_cum_duration Cumulative duration of all CPs in the slot.
158159
/// \param[in] first_hop_symbol Index of the first OFDM symbol of the current hop, within the slot.
@@ -174,22 +175,34 @@ static std::pair<float, optional<float>> preprocess_pilots_and_cfo(span<cf_t>
174175
unsigned i_layer);
175176

176177
/// \brief Estimates the noise energy of one hop.
177-
/// \param[in] pilots DM-RS pilots.
178-
/// \param[in] rx_pilots Received samples corresponding to DM-RS pilots.
179-
/// \param[in] estimates Estimated channel frequency response.
180-
/// \param[in] beta DM-RS-to-data amplitude gain (linear scale).
181-
/// \param[in] hop_symbols Number of OFDM symbols containing DM-RS pilots in the current hop.
182-
/// \param[in] hop_offset Number of OFDM symbols containing DM-RS pilots in the previous hop (set to 0 if the current
183-
/// hop is the first/only one).
184-
/// \param[in] i_layer Index of the selected layer.
178+
/// \param[in] pilots DM-RS pilots.
179+
/// \param[in] rx_pilots Received samples corresponding to DM-RS pilots.
180+
/// \param[in] estimates Estimated channel frequency response.
181+
/// \param[in] beta DM-RS-to-data amplitude gain (linear scale).
182+
/// \param[in] dmrs_mask Boolean mask identifying the OFDM symbols carrying DM-RS within the slot.
183+
/// \param[in] scs Subcarrier spacing.
184+
/// \param[in] cfo Carrier frequency offset.
185+
/// \param[in] cp_cum_duration Cumulative duration of all CPs in the slot.
186+
/// \param[in] first_hop_symbol Index of the first OFDM symbol of the current hop, within the slot.
187+
/// \param[in] last_hop_symbol Index of the last OFDM symbol of the current hop (not included), within the slot.
188+
/// \param[in] hop_symbols Number of OFDM symbols containing DM-RS pilots in the current hop.
189+
/// \param[in] hop_offset Number of OFDM symbols containing DM-RS pilots in the previous hop (set to 0 if the
190+
/// current hop is the first/only one).
191+
/// \param[in] i_layer Index of the selected layer.
185192
/// \return The noise energy for the current hop.
186-
static float estimate_noise(const dmrs_symbol_list& pilots,
187-
const dmrs_symbol_list& rx_pilots,
188-
span<const cf_t> estimates,
189-
float beta,
190-
unsigned hop_symbols,
191-
unsigned hop_offset,
192-
unsigned i_layer);
193+
static float estimate_noise(const dmrs_symbol_list& pilots,
194+
const dmrs_symbol_list& rx_pilots,
195+
span<const cf_t> estimates,
196+
float beta,
197+
const bounded_bitset<MAX_NSYMB_PER_SLOT>& dmrs_mask,
198+
const subcarrier_spacing& scs,
199+
optional<float> cfo,
200+
span<const float> cp_cum_duration,
201+
unsigned first_hop_symbol,
202+
unsigned last_hop_symbol,
203+
unsigned hop_symbols,
204+
unsigned hop_offset,
205+
unsigned i_layer);
193206

194207
/// \brief Estimates the time alignment based on one hop.
195208
///
@@ -336,13 +349,12 @@ void port_channel_estimator_average_impl::compute_layer_hop(srsran::channel_esti
336349
hop_offset,
337350
i_layer);
338351
epre += hop_results.first;
339-
340-
if (hop_results.second.has_value()) {
341-
float cfo_hop = hop_results.second.value();
352+
optional<float> cfo_hop = hop_results.second;
353+
if (cfo_hop.has_value()) {
342354
if (cfo_normalized.has_value()) {
343-
cfo_normalized = (cfo_normalized.value() + cfo_hop) / 2;
355+
cfo_normalized = (cfo_normalized.value() + cfo_hop.value()) / 2;
344356
} else {
345-
cfo_normalized = cfo_hop;
357+
cfo_normalized = cfo_hop.value();
346358
}
347359
}
348360

@@ -373,8 +385,19 @@ void port_channel_estimator_average_impl::compute_layer_hop(srsran::channel_esti
373385
rsrp += std::real(srsvec::dot_prod(filtered_pilots_lse, filtered_pilots_lse)) * beta_scaling * beta_scaling *
374386
static_cast<float>(nof_dmrs_symbols);
375387

376-
noise_var +=
377-
estimate_noise(pilots, rx_pilots, filtered_pilots_lse, beta_scaling, nof_dmrs_symbols, hop_offset, i_layer);
388+
noise_var += estimate_noise(pilots,
389+
rx_pilots,
390+
filtered_pilots_lse,
391+
beta_scaling,
392+
pattern.symbols,
393+
cfg.scs,
394+
cfo_hop,
395+
cp_cum_duration,
396+
first_symbol,
397+
last_symbol,
398+
nof_dmrs_symbols,
399+
hop_offset,
400+
i_layer);
378401

379402
time_alignment_s += estimate_time_alignment(filtered_pilots_lse, pattern, hop, cfg.scs, *ta_estimator);
380403

@@ -502,7 +525,7 @@ static std::pair<float, optional<float>> preprocess_pilots_and_cfo(span<cf_t>
502525
pilot_products, std::polar(1.0f, -TWOPI * (i_symbol + cp_cum_duration[i_symbol]) * cfo), pilot_products);
503526
srsvec::add(pilots_lse, pilot_products, pilots_lse);
504527
epre += std::real(srsvec::dot_prod(rx_pilots.get_symbol(i_dmrs, i_layer), rx_pilots.get_symbol(i_dmrs, i_layer)));
505-
i_dmrs++;
528+
++i_dmrs;
506529
};
507530

508531
dmrs_mask.for_each(i_dmrs_1 + 1, last_hop_symbol, combine_pilots);
@@ -511,13 +534,19 @@ static std::pair<float, optional<float>> preprocess_pilots_and_cfo(span<cf_t>
511534
return {epre, cfo};
512535
}
513536

514-
static float estimate_noise(const dmrs_symbol_list& pilots,
515-
const dmrs_symbol_list& rx_pilots,
516-
span<const cf_t> estimates,
517-
float beta,
518-
unsigned hop_symbols,
519-
unsigned hop_offset,
520-
unsigned i_layer)
537+
static float estimate_noise(const dmrs_symbol_list& pilots,
538+
const dmrs_symbol_list& rx_pilots,
539+
span<const cf_t> estimates,
540+
float beta,
541+
const bounded_bitset<MAX_NSYMB_PER_SLOT>& dmrs_mask,
542+
const subcarrier_spacing& scs,
543+
optional<float> cfo,
544+
span<const float> cp_cum_duration,
545+
unsigned first_hop_symbol,
546+
unsigned last_hop_symbol,
547+
unsigned hop_symbols,
548+
unsigned hop_offset,
549+
unsigned i_layer)
521550
{
522551
std::array<cf_t, MAX_RB * NRE> avg_estimates_buffer;
523552
std::array<cf_t, MAX_RB * NRE> predicted_obs_buffer;
@@ -528,15 +557,36 @@ static float estimate_noise(const dmrs_symbol_list& pilots,
528557

529558
span<cf_t> predicted_obs = span<cf_t>(predicted_obs_buffer).first(estimates.size());
530559
float noise_energy = 0.0F;
531-
for (unsigned i_symbol = 0; i_symbol != hop_symbols; ++i_symbol) {
532-
span<const cf_t> symbol_pilots = pilots.get_symbol(hop_offset + i_symbol, i_layer);
533-
span<const cf_t> symbol_rx_pilots = rx_pilots.get_symbol(i_symbol, i_layer);
534560

535-
srsvec::prod(scaled_estimates, symbol_pilots, predicted_obs);
536-
srsvec::add(predicted_obs, symbol_rx_pilots, predicted_obs);
561+
if (cfo.has_value()) {
562+
auto noise_cfo = [&, i_dmrs = 0](size_t i_symbol) mutable {
563+
span<const cf_t> symbol_pilots = pilots.get_symbol(hop_offset + i_dmrs, i_layer);
564+
span<const cf_t> symbol_rx_pilots = rx_pilots.get_symbol(i_dmrs, i_layer);
565+
566+
srsvec::prod(scaled_estimates, symbol_pilots, predicted_obs);
567+
srsvec::sc_prod(
568+
predicted_obs, std::polar(1.0f, TWOPI * (i_symbol + cp_cum_duration[i_symbol]) * cfo.value()), predicted_obs);
569+
srsvec::add(predicted_obs, symbol_rx_pilots, predicted_obs);
570+
571+
noise_energy += std::real(srsvec::dot_prod(predicted_obs, predicted_obs));
572+
++i_dmrs;
573+
};
537574

538-
noise_energy += std::real(srsvec::dot_prod(predicted_obs, predicted_obs));
575+
dmrs_mask.for_each(first_hop_symbol, last_hop_symbol, noise_cfo);
576+
} else {
577+
auto noise_no_cfo = [&, i_dmrs = 0](size_t i_symbol) mutable {
578+
span<const cf_t> symbol_pilots = pilots.get_symbol(hop_offset + i_dmrs, i_layer);
579+
span<const cf_t> symbol_rx_pilots = rx_pilots.get_symbol(i_dmrs, i_layer);
580+
581+
srsvec::prod(scaled_estimates, symbol_pilots, predicted_obs);
582+
srsvec::add(predicted_obs, symbol_rx_pilots, predicted_obs);
583+
584+
noise_energy += std::real(srsvec::dot_prod(predicted_obs, predicted_obs));
585+
++i_dmrs;
586+
};
587+
dmrs_mask.for_each(first_hop_symbol, last_hop_symbol, noise_no_cfo);
539588
}
589+
540590
return noise_energy;
541591
}
542592

0 commit comments

Comments
 (0)