@@ -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