Skip to content

Commit 152aeaf

Browse files
committed
phy: integrate transform precoding in PUSCH demodulator
phy: fix typo
1 parent 8d7279b commit 152aeaf

File tree

20 files changed

+224
-173
lines changed

20 files changed

+224
-173
lines changed

include/srsran/phy/upper/channel_processors/pusch/factories.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#pragma once
1212

1313
#include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_factory.h"
14+
#include "srsran/phy/generic_functions/transform_precoding/transform_precoding_factories.h"
1415
#include "srsran/phy/upper/channel_coding/channel_coding_factories.h"
1516
#include "srsran/phy/upper/channel_modulation/channel_modulation_factories.h"
1617
#include "srsran/phy/upper/channel_processors/pusch/pusch_decoder.h"
@@ -76,8 +77,10 @@ class pusch_demodulator_factory
7677

7778
std::shared_ptr<pusch_demodulator_factory>
7879
create_pusch_demodulator_factory_sw(std::shared_ptr<channel_equalizer_factory> equalizer_factory,
80+
std::shared_ptr<transform_precoder_factory> precoder_factory,
7981
std::shared_ptr<channel_modulation_factory> demodulation_factory,
8082
std::shared_ptr<pseudo_random_generator_factory> prg_factory,
83+
unsigned max_nof_prb,
8184
bool enable_evm = false,
8285
bool enable_post_eq_sinr = false);
8386

include/srsran/phy/upper/channel_processors/pusch/pusch_demodulator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ class pusch_demodulator
5858
unsigned n_id;
5959
/// Number of transmit layers.
6060
unsigned nof_tx_layers;
61+
/// Set to true for enabling transform precoding.
62+
bool enable_transform_precoding;
6163
/// Receive antenna port indices the PUSCH transmission is mapped to.
6264
static_vector<uint8_t, MAX_PORTS> rx_ports;
6365
};

include/srsran/ran/pusch/pusch_constants.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ inline constexpr units::bits get_max_codeword_size(unsigned nof_prb, unsigned no
5151
return units::bits{get_codeword_max_symbols(nof_prb, nof_layers) * pusch_constants::MAX_MODULATION_ORDER};
5252
}
5353

54+
/// Maximum number of bits per OFDM symbol.
55+
constexpr unsigned MAX_NOF_BITS_PER_OFDM_SYMBOL = MAX_NOF_LAYERS * MAX_RB * NRE * pusch_constants::MAX_MODULATION_ORDER;
56+
5457
/// Maximum number of OFDM symbols carrying DM-RS in a slot is at most \f$4 \times 2\f$, being 4 the maximum
5558
/// number of positions \f$\bar{l}\f$ and 2 the maximum number of indices \f$l'\f$, as per TS38.211 Section 6.4.1.1.
5659
static constexpr unsigned MAX_NOF_DMRS_SYMBOLS = 4 * 2;

lib/phy/upper/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ target_link_libraries(srsran_upper_phy
3535
srsran_uplink_processor
3636
srsran_phy_support
3737
srsran_generic_funcs
38+
srsran_transform_precoding
3839
srsran_channel_equalizer)
3940

4041
add_library(log_likelihood_ratio log_likelihood_ratio.cpp)

lib/phy/upper/channel_processors/pusch/factories.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "pusch_processor_pool.h"
2020
#include "pusch_processor_validator_impl.h"
2121
#include "ulsch_demultiplex_impl.h"
22+
#include "srsran/phy/generic_functions/transform_precoding/transform_precoding_factories.h"
2223
#include "srsran/phy/upper/channel_modulation/channel_modulation_factories.h"
2324
#include "srsran/phy/upper/channel_processors/pusch/pusch_processor_result_notifier.h"
2425
#include "srsran/phy/upper/sequence_generators/sequence_generator_factories.h"
@@ -143,32 +144,41 @@ class pusch_demodulator_factory_generic : public pusch_demodulator_factory
143144
evm_calc = demodulation_factory->create_evm_calculator();
144145
}
145146
return std::make_unique<pusch_demodulator_impl>(equalizer_factory->create(),
147+
precoder_factory->create(),
146148
demodulation_factory->create_demodulation_mapper(),
147149
std::move(evm_calc),
148150
prg_factory->create(),
151+
max_nof_prb,
149152
enable_post_eq_sinr);
150153
}
151154

152155
pusch_demodulator_factory_generic(std::shared_ptr<channel_equalizer_factory> equalizer_factory_,
156+
std::shared_ptr<transform_precoder_factory> precoder_factory_,
153157
std::shared_ptr<channel_modulation_factory> demodulation_factory_,
154158
std::shared_ptr<pseudo_random_generator_factory> prg_factory_,
159+
unsigned max_nof_prb_,
155160
bool enable_evm_,
156161
bool enable_post_eq_sinr_) :
157162
equalizer_factory(std::move(equalizer_factory_)),
163+
precoder_factory(std::move(precoder_factory_)),
158164
demodulation_factory(std::move(demodulation_factory_)),
159165
prg_factory(std::move(prg_factory_)),
166+
max_nof_prb(max_nof_prb_),
160167
enable_evm(enable_evm_),
161168
enable_post_eq_sinr(enable_post_eq_sinr_)
162169
{
163170
srsran_assert(equalizer_factory, "Invalid equalizer factory.");
171+
srsran_assert(precoder_factory, "Invalid transform precoder factory.");
164172
srsran_assert(demodulation_factory, "Invalid demodulation factory.");
165173
srsran_assert(prg_factory, "Invalid PRG factory.");
166174
}
167175

168176
private:
169177
std::shared_ptr<channel_equalizer_factory> equalizer_factory;
178+
std::shared_ptr<transform_precoder_factory> precoder_factory;
170179
std::shared_ptr<channel_modulation_factory> demodulation_factory;
171180
std::shared_ptr<pseudo_random_generator_factory> prg_factory;
181+
unsigned max_nof_prb;
172182
bool enable_evm;
173183
bool enable_post_eq_sinr;
174184
};
@@ -327,14 +337,18 @@ srsran::create_pusch_decoder_factory_hw(const pusch_decoder_factory_hw_configura
327337

328338
std::shared_ptr<pusch_demodulator_factory>
329339
srsran::create_pusch_demodulator_factory_sw(std::shared_ptr<channel_equalizer_factory> equalizer_factory,
340+
std::shared_ptr<transform_precoder_factory> precoder_factory,
330341
std::shared_ptr<channel_modulation_factory> demodulation_factory,
331342
std::shared_ptr<pseudo_random_generator_factory> prg_factory,
343+
unsigned max_nof_prb,
332344
bool enable_evm,
333345
bool enable_post_eq_sinr)
334346
{
335347
return std::make_shared<pusch_demodulator_factory_generic>(std::move(equalizer_factory),
348+
std::move(precoder_factory),
336349
std::move(demodulation_factory),
337350
std::move(prg_factory),
351+
max_nof_prb,
338352
enable_evm,
339353
enable_post_eq_sinr);
340354
}

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

Lines changed: 77 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -149,115 +149,110 @@ void pusch_demodulator_impl::demodulate(pusch_codeword_buffer& codeword_buf
149149
float noise_var_accumulate = 0.0;
150150
float evm_accumulate = 0.0;
151151

152+
// Process each OFDM symbol.
152153
for (unsigned i_symbol = config.start_symbol_index, i_symbol_end = config.start_symbol_index + config.nof_symbols;
153154
i_symbol != i_symbol_end;
154155
++i_symbol) {
155156
// Select RE mask for the symbol.
156157
re_symbol_mask_type& symbol_re_mask = config.dmrs_symb_pos.test(i_symbol) ? re_mask_dmrs : re_mask;
157158

159+
// Count the number of active RE in the symbol.
160+
unsigned nof_re_symbol = symbol_re_mask.count();
161+
158162
// Skip symbol if it does not contain data.
159-
if (symbol_re_mask.none()) {
163+
if (nof_re_symbol == 0) {
160164
continue;
161165
}
162166

163-
// Process subcarriers in groups.
164-
for (unsigned i_subc = symbol_re_mask.find_lowest(), i_subc_end = symbol_re_mask.find_highest() + 1;
165-
i_subc != i_subc_end;) {
166-
// Calculate the remainder number of subcarriers to process for the current OFDM symbol.
167-
unsigned nof_block_subc = i_subc_end - i_subc;
168-
169-
// Limit number of RE to the maximum block size.
170-
nof_block_subc = std::min(nof_block_subc, MAX_BLOCK_SIZE / nof_bits_per_re);
171-
172-
// Get a view of the codeword buffer destination.
173-
span<log_likelihood_ratio> codeword_block = codeword_buffer.get_next_block_view(nof_block_subc * nof_bits_per_re);
167+
// Resize equalizer output buffers.
168+
span<cf_t> eq_re = span<cf_t>(temp_eq_re).first(nof_re_symbol * config.nof_tx_layers);
169+
span<float> eq_noise_vars = span<float>(temp_eq_noise_vars).first(nof_re_symbol * config.nof_tx_layers);
174170

175-
// If the codeword is empty, skip the rest of the symbol.
176-
if (codeword_block.empty()) {
177-
unsigned nof_remainder_re = symbol_re_mask.slice(i_subc, symbol_re_mask.size()).count();
178-
srsran_assert(nof_remainder_re == 0, "There are {} remaining RE.", nof_remainder_re);
179-
break;
180-
}
171+
// Extract the data symbols and channel estimates from the resource grid.
172+
const re_buffer_reader<cbf16_t>& ch_re = get_ch_data_re(grid, i_symbol, symbol_re_mask, config.rx_ports);
173+
const channel_equalizer::ch_est_list& ch_estimates =
174+
get_ch_data_estimates(estimates, i_symbol, config.nof_tx_layers, symbol_re_mask, config.rx_ports);
181175

182-
// Limit block size if the codeword block is smaller.
183-
srsran_assert(codeword_block.size() % nof_bits_per_re == 0,
184-
"The codeword block size (i.e., {}) must be multiple of the number of bits per RE (i.e., {}).",
185-
codeword_block.size(),
186-
nof_bits_per_re);
187-
188-
// Extract mask for the block.
189-
// First, get the mask of data REs in the current block of received symbols.
190-
re_symbol_mask_type block_re_mask = symbol_re_mask.slice(i_subc, i_subc + nof_block_subc);
191-
// Next, get the number of subcarriers needed to carry the current codeword block.
192-
unsigned nof_required_subc = static_cast<unsigned>(codeword_block.size()) / nof_bits_per_re;
193-
// Ensure the number of data REs in the block of received symbols is not larger than the codeword block (expressed
194-
// as a number of subcarriers).
195-
while (block_re_mask.count() > nof_required_subc) {
196-
--nof_block_subc;
197-
block_re_mask = symbol_re_mask.slice(i_subc, i_subc + nof_block_subc);
198-
}
176+
// Extract the Rx port noise variances from the channel estimation.
177+
for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) {
178+
noise_var_estimates[i_port] = estimates.get_noise_variance(i_port, 0);
179+
}
199180

200-
// Number of data Resource Elements in a slot for a single Rx port.
201-
unsigned nof_re_port = static_cast<unsigned>(block_re_mask.count());
181+
// Equalize channels and, for each Tx layer, combine contribution from all Rx antenna ports.
182+
equalizer->equalize(
183+
eq_re, eq_noise_vars, ch_re, ch_estimates, span<float>(noise_var_estimates).first(nof_rx_ports), 1.0F);
202184

203-
// Skip block if no data.
204-
if (nof_re_port == 0) {
205-
i_subc += nof_block_subc;
206-
continue;
207-
}
185+
// Revert transform precoding for the entire OFDM symbol.
186+
if (config.enable_transform_precoding) {
187+
srsran_assert(config.nof_tx_layers == 1,
188+
"Transform precoding is only possible with one layer (i.e. {}).",
189+
config.nof_tx_layers);
190+
precoder->deprecode_ofdm_symbol(eq_re, eq_re);
191+
}
208192

209-
// Resize equalizer output buffers.
210-
span<cf_t> eq_re = span<cf_t>(temp_eq_re).first(nof_re_port * config.nof_tx_layers);
211-
span<float> eq_noise_vars = span<float>(temp_eq_noise_vars).first(nof_re_port * config.nof_tx_layers);
193+
// Estimate post equalization Signal-to-Interference-plus-Noise Ratio.
194+
if (compute_post_eq_sinr) {
195+
noise_var_accumulate +=
196+
std::accumulate(eq_noise_vars.begin(), eq_noise_vars.end(), 0.0F, [&sinr_softbit_count](float sum, float in) {
197+
// Exclude outliers with infinite variance. This makes sure that handling of the DC carrier does not skew
198+
// the SINR results.
199+
if (std::isinf(in)) {
200+
return sum;
201+
}
202+
203+
++sinr_softbit_count;
204+
return sum + in;
205+
});
206+
}
212207

213-
// Extract the data symbols and channel estimates from the resource grid.
214-
const re_buffer_reader<cbf16_t>& ch_re = get_ch_data_re(grid, i_symbol, i_subc, block_re_mask, config.rx_ports);
215-
const channel_equalizer::ch_est_list& ch_estimates =
216-
get_ch_data_estimates(estimates, i_symbol, i_subc, config.nof_tx_layers, block_re_mask, config.rx_ports);
208+
// Counts the number of processed RE for the OFDM symbol.
209+
unsigned count_re_symbol = 0;
217210

218-
// Increment subcarrier count.
219-
i_subc += nof_block_subc;
211+
// Process subcarriers in groups.
212+
while (count_re_symbol != nof_re_symbol) {
213+
// Calculate the remainder number of subcarriers to process for the current OFDM symbol.
214+
unsigned remain_nof_subc = nof_re_symbol - count_re_symbol;
220215

221-
// Extract the Rx port noise variances from the channel estimation.
222-
for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) {
223-
noise_var_estimates[i_port] = estimates.get_noise_variance(i_port, 0);
224-
}
216+
// Get a view of the codeword buffer destination.
217+
span<log_likelihood_ratio> codeword = codeword_buffer.get_next_block_view(remain_nof_subc * nof_bits_per_re);
225218

226-
// Equalize channels and, for each Tx layer, combine contribution from all Rx antenna ports.
227-
equalizer->equalize(
228-
eq_re, eq_noise_vars, ch_re, ch_estimates, span<float>(noise_var_estimates).first(nof_rx_ports), 1.0F);
229-
230-
// Estimate post equalization Signal-to-Interference-plus-Noise Ratio.
231-
if (compute_post_eq_sinr) {
232-
noise_var_accumulate += std::accumulate(
233-
eq_noise_vars.begin(), eq_noise_vars.end(), 0.0F, [&sinr_softbit_count](float sum, float in) {
234-
// Exclude outliers with infinite variance. This makes sure that handling of the DC carrier does not skew
235-
// the SINR results.
236-
if (std::isinf(in)) {
237-
return sum;
238-
}
239-
240-
++sinr_softbit_count;
241-
return sum + in;
242-
});
243-
}
219+
// Limit block size if the codeword block is smaller.
220+
srsran_assert(codeword.size() % nof_bits_per_re == 0,
221+
"The codeword block size (i.e., {}) must be multiple of the number of bits per RE (i.e., {}).",
222+
codeword.size(),
223+
nof_bits_per_re);
244224

245-
// Get codeword buffer.
246-
unsigned nof_block_softbits = nof_re_port * nof_bits_per_re;
247-
span<log_likelihood_ratio> codeword = codeword_block.first(nof_block_softbits);
225+
// Select equalizer output.
226+
unsigned nof_block_softbits = codeword.size();
227+
unsigned codeword_block_offset = count_re_symbol * config.nof_tx_layers;
228+
unsigned codeword_block_size = nof_block_softbits / get_bits_per_symbol(config.modulation);
229+
span<const cf_t> eq_re_block = eq_re.subspan(codeword_block_offset, codeword_block_size);
230+
span<const float> eq_noise_vars_block = eq_noise_vars.subspan(codeword_block_offset, codeword_block_size);
248231

249232
// Build LLRs from channel symbols.
250-
demapper->demodulate_soft(codeword, eq_re, eq_noise_vars, config.modulation);
233+
demapper->demodulate_soft(codeword, eq_re_block, eq_noise_vars_block, config.modulation);
251234

252235
// Calculate EVM only if it is available.
253236
if (evm_calc) {
254-
unsigned nof_re_evm = eq_re.size();
255-
evm_accumulate += static_cast<float>(nof_re_evm) * evm_calc->calculate(codeword, eq_re, config.modulation);
256-
evm_symbol_count += nof_re_evm;
237+
evm_accumulate +=
238+
static_cast<float>(codeword_block_size) * evm_calc->calculate(codeword, eq_re_block, config.modulation);
239+
evm_symbol_count += codeword_block_size;
257240
}
258241

259-
// Update and notify statistics.
260-
if (i_subc == i_subc_end) {
242+
// Generate scrambling sequence.
243+
static_bit_buffer<pusch_constants::MAX_NOF_BITS_PER_OFDM_SYMBOL> scrambling_seq(nof_block_softbits);
244+
descrambler->generate(scrambling_seq);
245+
246+
// Revert scrambling.
247+
revert_scrambling(codeword, codeword, scrambling_seq);
248+
249+
// Increment the number of processed RE within the OFDM symbol.
250+
count_re_symbol += nof_block_softbits / nof_bits_per_re;
251+
252+
// Update and notify statistics if it is the last processed block for the OFDM symbol. The provisional stats must
253+
// be notified earlier than the new processed block to ensure the stats are available upon the notification of the
254+
// results.
255+
if (count_re_symbol == nof_re_symbol) {
261256
if ((sinr_softbit_count != 0) && (noise_var_accumulate > 0.0)) {
262257
float mean_noise_var = noise_var_accumulate / static_cast<float>(sinr_softbit_count);
263258
stats.sinr_dB.emplace(-convert_power_to_dB(mean_noise_var));
@@ -270,13 +265,6 @@ void pusch_demodulator_impl::demodulate(pusch_codeword_buffer& codeword_buf
270265
notifier.on_provisional_stats(stats);
271266
}
272267

273-
// Generate scrambling sequence.
274-
static_bit_buffer<MAX_BLOCK_SIZE> scrambling_seq(nof_block_softbits);
275-
descrambler->generate(scrambling_seq);
276-
277-
// Revert scrambling.
278-
revert_scrambling(codeword, codeword, scrambling_seq);
279-
280268
// Notify a new processed block.
281269
codeword_buffer.on_new_block(codeword, scrambling_seq);
282270
}

0 commit comments

Comments
 (0)