mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
Segregate the LLR and channel compensation related common functions into different files
Signed-off-by: Rupanjali <rupanjali.srivastava@openairinterface.org>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
# SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
|
||||
add_library(nr_phy_common src/nr_phy_common.c)
|
||||
add_library(nr_phy_common src/nr_phy_common.c
|
||||
src/nr_channel_compensation.c
|
||||
src/nr_compute_llr.c)
|
||||
target_link_libraries(nr_phy_common PRIVATE UTIL PHY_COMMON)
|
||||
target_include_directories(nr_phy_common PUBLIC inc/)
|
||||
|
||||
|
||||
47
openair1/PHY/nr_phy_common/inc/nr_channel_compensation.h
Normal file
47
openair1/PHY/nr_phy_common/inc/nr_channel_compensation.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#ifndef __NR_CHANNEL_COMPENSATION__H__
|
||||
#define __NR_CHANNEL_COMPENSATION__H__
|
||||
|
||||
#include "PHY/impl_defs_top.h"
|
||||
|
||||
/**
|
||||
* @brief Common channel compensation function shared by DL (PDSCH) and UL (PUSCH) paths.
|
||||
*
|
||||
* Computes matched-filter output (rxComp) and channel magnitude arrays used for LLR
|
||||
* computation. MRC across Rx antennas is performed inline: for each layer, contributions
|
||||
* from all Rx antennas are accumulated into rxComp[layer * nb_rx_ant][symbol * buffer_length].
|
||||
* Uses AVX2 (256-bit SIMD) for throughput.
|
||||
*
|
||||
* @param buffer_length Number of complex samples per symbol (must be a multiple of 8)
|
||||
* @param nb_rx_ant Number of Rx antennas
|
||||
* @param nb_layers Number of spatial layers
|
||||
* @param rxFext Extracted received signal [nb_rx_ant][buffer_length]
|
||||
* @param chFext Extracted channel estimates [nb_layers][nb_rx_ant][buffer_length]
|
||||
* @param ch_maga Output magnitude array for threshold 'a' [nb_layers][buffer_length]
|
||||
* @param ch_magb Output magnitude array for threshold 'b' [nb_layers][buffer_length]
|
||||
* @param ch_magc Output magnitude array for threshold 'c' [nb_layers][buffer_length]
|
||||
* @param rxComp Output compensated signal; row [l * nb_rx_ant] holds the MRC result
|
||||
* for layer l at offset [symbol * buffer_length]
|
||||
* @param rho Tx-correlation matrix [nb_layers][nb_layers][buffer_length], or NULL
|
||||
* @param mod_order Modulation order (2=QPSK, 4=16QAM, 6=64QAM, 8=256QAM)
|
||||
* @param symbol OFDM symbol index (used to compute offset into rxComp rows)
|
||||
* @param output_shift Right-shift applied after each complex multiply
|
||||
*/
|
||||
void nr_channel_compensation(uint32_t buffer_length,
|
||||
int nb_rx_ant,
|
||||
int nb_layers,
|
||||
c16_t rxFext[nb_rx_ant][buffer_length],
|
||||
c16_t chFext[nb_layers][nb_rx_ant][buffer_length],
|
||||
c16_t **ch_maga,
|
||||
c16_t **ch_magb,
|
||||
c16_t **ch_magc,
|
||||
c16_t **rxComp,
|
||||
c16_t (*rho)[nb_layers][buffer_length],
|
||||
int mod_order,
|
||||
uint32_t symbol,
|
||||
uint32_t output_shift);
|
||||
|
||||
#endif /* __NR_CHANNEL_COMPENSATION__H__ */
|
||||
141
openair1/PHY/nr_phy_common/inc/nr_compute_llr.h
Normal file
141
openair1/PHY/nr_phy_common/inc/nr_compute_llr.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#ifndef __NR_COMPUTE_LLR__H__
|
||||
#define __NR_COMPUTE_LLR__H__
|
||||
|
||||
#include "PHY/impl_defs_top.h"
|
||||
|
||||
/**
|
||||
* @brief Per-layer LLR dispatch for single-stream or post-MMSE output.
|
||||
*
|
||||
* Selects the appropriate single-layer LLR function based on modulation order.
|
||||
*
|
||||
* @param rxdataF_comp Compensated received signal
|
||||
* @param ch_mag Channel magnitude (threshold a), used for 16/64/256QAM
|
||||
* @param ch_magb Channel magnitude (threshold b), used for 64/256QAM
|
||||
* @param ch_magc Channel magnitude (threshold c), used for 256QAM
|
||||
* @param llr Output LLR buffer
|
||||
* @param nb_re Number of resource elements
|
||||
* @param symbol OFDM symbol index (used only in AssertFatal message)
|
||||
* @param mod_order Modulation order (2=QPSK, 4=16QAM, 6=64QAM, 8=256QAM)
|
||||
*/
|
||||
void nr_compute_llr(c16_t *rxdataF_comp,
|
||||
c16_t *ch_mag,
|
||||
c16_t *ch_magb,
|
||||
c16_t *ch_magc,
|
||||
int16_t *llr,
|
||||
uint32_t nb_re,
|
||||
uint8_t symbol,
|
||||
uint8_t mod_order);
|
||||
|
||||
/**
|
||||
* @brief 2-layer ML-LLR for QPSK×QPSK.
|
||||
*
|
||||
* Computes LLRs for stream 0 in the presence of interference from stream 1,
|
||||
* both modulated with QPSK. Uses 128-bit SIMD on aarch64, 256-bit AVX2 elsewhere.
|
||||
*
|
||||
* @param stream0_in MF output for stream 0: y0' = h0'·y0
|
||||
* @param stream1_in MF output for stream 1: y1' = h1'·y0
|
||||
* @param stream0_out Output LLRs for stream 0
|
||||
* @param rho01 Channel cross-correlation: rho01 = h0'·h1
|
||||
* @param length Number of resource elements
|
||||
*/
|
||||
void nr_qpsk_llr_2layer(c16_t *stream0_in, c16_t *stream1_in,
|
||||
int16_t *stream0_out, c16_t *rho01, uint32_t length);
|
||||
|
||||
/**
|
||||
* @brief 2-layer ML-LLR for 16QAM×16QAM.
|
||||
*
|
||||
* @param stream0_in MF output for stream 0
|
||||
* @param stream1_in MF output for stream 1
|
||||
* @param ch_mag Channel magnitude for stream 0
|
||||
* @param ch_mag_i Channel magnitude for stream 1
|
||||
* @param stream0_out Output LLRs for stream 0
|
||||
* @param rho01 Channel cross-correlation
|
||||
* @param length Number of resource elements
|
||||
*/
|
||||
void nr_qam16_llr_2layer(c16_t *stream0_in, c16_t *stream1_in,
|
||||
c16_t *ch_mag, c16_t *ch_mag_i,
|
||||
int16_t *stream0_out, c16_t *rho01, uint32_t length);
|
||||
|
||||
/**
|
||||
* @brief 2-layer ML-LLR for 64QAM×64QAM.
|
||||
*
|
||||
* @param stream0_in MF output for stream 0
|
||||
* @param stream1_in MF output for stream 1
|
||||
* @param ch_mag Channel magnitude (threshold a) for stream 0
|
||||
* @param ch_mag_i Channel magnitude (threshold a) for stream 1
|
||||
* @param stream0_out Output LLRs for stream 0
|
||||
* @param rho01 Channel cross-correlation
|
||||
* @param length Number of resource elements
|
||||
*/
|
||||
void nr_qam64_llr_2layer(c16_t *stream0_in, c16_t *stream1_in,
|
||||
c16_t *ch_mag, c16_t *ch_mag_i,
|
||||
int16_t *stream0_out, c16_t *rho01, uint32_t length);
|
||||
|
||||
/**
|
||||
* @brief Compute ML LLRs for both streams of a 2-layer MIMO transmission.
|
||||
*
|
||||
* Dispatches to nr_qpsk_llr_2layer / nr_qam16_llr_2layer / nr_qam64_llr_2layer
|
||||
* for each stream in sequence.
|
||||
*
|
||||
* @param rxdataF_comp0 Compensated received signal for layer 0
|
||||
* @param rxdataF_comp1 Compensated received signal for layer 1
|
||||
* @param ch_mag0 Channel magnitude for layer 0
|
||||
* @param ch_mag1 Channel magnitude for layer 1
|
||||
* @param llr_layers0 Output LLR buffer for layer 0
|
||||
* @param llr_layers1 Output LLR buffer for layer 1
|
||||
* @param rho0 Cross-correlation rho[0][1]
|
||||
* @param rho1 Cross-correlation rho[1][0]
|
||||
* @param nb_re Number of resource elements
|
||||
* @param mod_order Modulation order (2=QPSK, 4=16QAM, 6=64QAM)
|
||||
*/
|
||||
void nr_compute_ML_llr(c16_t *rxdataF_comp0,
|
||||
c16_t *rxdataF_comp1,
|
||||
c16_t *ch_mag0,
|
||||
c16_t *ch_mag1,
|
||||
int16_t *llr_layers0,
|
||||
int16_t *llr_layers1,
|
||||
c16_t *rho0,
|
||||
c16_t *rho1,
|
||||
uint32_t nb_re,
|
||||
uint8_t mod_order);
|
||||
|
||||
/**
|
||||
* @brief MMSE equalizer for 2-layer MIMO, followed by per-layer LLR computation.
|
||||
*
|
||||
* Performs 2×2 MMSE equalization, updates ch_mag arrays with post-equalization
|
||||
* effective SNR, and computes per-layer LLRs via nr_compute_llr.
|
||||
*
|
||||
* @param rxdataF_comp Compensated received signal [nl * nb_rx_ant][buffer_length]
|
||||
* @param buffer_length Samples per symbol
|
||||
* @param nb_rx_ant Number of Rx antennas
|
||||
* @param ch_mag Channel magnitude threshold 'a' [2][buffer_length]
|
||||
* @param ch_magb Channel magnitude threshold 'b' [2][buffer_length]
|
||||
* @param ch_magc Channel magnitude threshold 'c' [2][buffer_length]
|
||||
* @param ch_estimates_ext Channel estimates [2][nb_rx_ant][buffer_length]
|
||||
* @param nb_rb Number of allocated resource blocks
|
||||
* @param mod_order Modulation order
|
||||
* @param shift Right-shift for internal fixed-point arithmetic
|
||||
* @param symbol OFDM symbol index
|
||||
* @param length Number of resource elements to process
|
||||
* @param noise_var Noise variance estimate
|
||||
* @return 0 on success
|
||||
*/
|
||||
uint8_t nr_mmse_2layers(c16_t **rxdataF_comp,
|
||||
uint32_t buffer_length,
|
||||
int nb_rx_ant,
|
||||
c16_t **ch_mag,
|
||||
c16_t **ch_magb,
|
||||
c16_t **ch_magc,
|
||||
c16_t ch_estimates_ext[][nb_rx_ant][buffer_length],
|
||||
unsigned short nb_rb,
|
||||
unsigned char mod_order,
|
||||
int shift,
|
||||
unsigned char symbol,
|
||||
int length,
|
||||
uint32_t noise_var);
|
||||
|
||||
#endif /* __NR_COMPUTE_LLR__H__ */
|
||||
@@ -388,80 +388,6 @@ bool check_rb_in_bitmap(const freq_alloc_bitmap_t *alloc, int rb);
|
||||
freq_alloc_bitmap_t set_start_end_from_bitmap(int size, int alloc_size, const uint8_t bitmap[alloc_size]);
|
||||
freq_alloc_bitmap_t set_bitmap_from_start_size(int start, int size);
|
||||
|
||||
/**
|
||||
* @brief Common channel compensation function shared by DL (PDSCH) and UL (PUSCH) paths.
|
||||
*
|
||||
* Computes matched-filter output (rxComp) and channel magnitude arrays used for LLR
|
||||
* computation. MRC across Rx antennas is performed inline: for each layer, contributions
|
||||
* from all Rx antennas are accumulated into rxComp[layer * nb_rx_ant][symbol * buffer_length].
|
||||
* Uses AVX2 (256-bit SIMD) for throughput.
|
||||
*
|
||||
* @param buffer_length Number of complex samples per symbol (must be a multiple of 8)
|
||||
* @param nb_rx_ant Number of Rx antennas
|
||||
* @param nb_layers Number of spatial layers
|
||||
* @param rxFext Extracted received signal [nb_rx_ant][buffer_length]
|
||||
* @param chFext Extracted channel estimates [nb_layers][nb_rx_ant][buffer_length]
|
||||
* @param ch_maga Output magnitude array for threshold 'a' [nb_layers][buffer_length]
|
||||
* @param ch_magb Output magnitude array for threshold 'b' [nb_layers][buffer_length]
|
||||
* @param ch_magc Output magnitude array for threshold 'c' [nb_layers][buffer_length]
|
||||
* @param rxComp Output compensated signal; row [l * nb_rx_ant] holds the MRC result
|
||||
* for layer l at offset [symbol * buffer_length]
|
||||
* @param rho Tx-correlation matrix [nb_layers][nb_layers][buffer_length], or NULL
|
||||
* @param mod_order Modulation order (2=QPSK, 4=16QAM, 6=64QAM, 8=256QAM)
|
||||
* @param symbol OFDM symbol index (used to compute offset into rxComp rows)
|
||||
* @param output_shift Right-shift applied after each complex multiply
|
||||
*/
|
||||
void nr_channel_compensation(uint32_t buffer_length,
|
||||
int nb_rx_ant,
|
||||
int nb_layers,
|
||||
c16_t rxFext[nb_rx_ant][buffer_length],
|
||||
c16_t chFext[nb_layers][nb_rx_ant][buffer_length],
|
||||
c16_t **ch_maga,
|
||||
c16_t **ch_magb,
|
||||
c16_t **ch_magc,
|
||||
c16_t **rxComp,
|
||||
c16_t (*rho)[nb_layers][buffer_length],
|
||||
int mod_order,
|
||||
uint32_t symbol,
|
||||
uint32_t output_shift);
|
||||
|
||||
void nr_compute_llr(c16_t *rxdataF_comp,
|
||||
c16_t *ch_mag,
|
||||
c16_t *ch_magb,
|
||||
c16_t *ch_magc,
|
||||
int16_t *llr,
|
||||
uint32_t nb_re,
|
||||
uint8_t symbol,
|
||||
uint8_t mod_order);
|
||||
|
||||
void nr_qpsk_llr_2layer(c16_t *stream0_in, c16_t *stream1_in,
|
||||
int16_t *stream0_out, c16_t *rho01, uint32_t length);
|
||||
|
||||
void nr_qam16_llr_2layer(c16_t *stream0_in, c16_t *stream1_in,
|
||||
c16_t *ch_mag, c16_t *ch_mag_i,
|
||||
int16_t *stream0_out, c16_t *rho01, uint32_t length);
|
||||
|
||||
void nr_qam64_llr_2layer(c16_t *stream0_in, c16_t *stream1_in,
|
||||
c16_t *ch_mag, c16_t *ch_mag_i,
|
||||
int16_t *stream0_out, c16_t *rho01, uint32_t length);
|
||||
|
||||
void nr_compute_ML_llr(c16_t *rxdataF_comp0, c16_t *rxdataF_comp1,
|
||||
c16_t *ch_mag0, c16_t *ch_mag1,
|
||||
int16_t *llr_layers0, int16_t *llr_layers1,
|
||||
c16_t *rho0, c16_t *rho1,
|
||||
uint32_t nb_re, uint8_t mod_order);
|
||||
|
||||
uint8_t nr_mmse_2layers(c16_t **rxdataF_comp,
|
||||
uint32_t buffer_length,
|
||||
int nb_rx_ant,
|
||||
c16_t **ch_mag,
|
||||
c16_t **ch_magb,
|
||||
c16_t **ch_magc,
|
||||
c16_t ul_ch_estimates_ext[][nb_rx_ant][buffer_length],
|
||||
unsigned short nb_rb,
|
||||
unsigned char mod_order,
|
||||
int shift,
|
||||
unsigned char symbol,
|
||||
int length,
|
||||
uint32_t noise_var);
|
||||
#include "nr_channel_compensation.h"
|
||||
#include "nr_compute_llr.h"
|
||||
#endif
|
||||
|
||||
114
openair1/PHY/nr_phy_common/src/nr_channel_compensation.c
Normal file
114
openair1/PHY/nr_phy_common/src/nr_channel_compensation.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#include "nr_channel_compensation.h"
|
||||
#include "bits.h"
|
||||
#include <complex.h>
|
||||
#include "PHY/sse_intrin.h"
|
||||
#include "PHY/impl_defs_top.h"
|
||||
#ifdef __aarch64__
|
||||
#define USE_128BIT
|
||||
#endif
|
||||
|
||||
void nr_channel_compensation(uint32_t buffer_length,
|
||||
int nb_rx_ant,
|
||||
int nb_layers,
|
||||
c16_t rxFext[nb_rx_ant][buffer_length],
|
||||
c16_t chFext[nb_layers][nb_rx_ant][buffer_length],
|
||||
c16_t **ch_maga,
|
||||
c16_t **ch_magb,
|
||||
c16_t **ch_magc,
|
||||
c16_t **rxComp,
|
||||
c16_t (*rho)[nb_layers][buffer_length],
|
||||
int mod_order,
|
||||
uint32_t symbol,
|
||||
uint32_t output_shift)
|
||||
{
|
||||
simde__m256i QAM_ampa_256 = simde_mm256_setzero_si256();
|
||||
simde__m256i QAM_ampb_256 = simde_mm256_setzero_si256();
|
||||
simde__m256i QAM_ampc_256 = simde_mm256_setzero_si256();
|
||||
|
||||
if (mod_order == 4) {
|
||||
QAM_ampa_256 = simde_mm256_set1_epi16(QAM16_n1);
|
||||
} else if (mod_order == 6) {
|
||||
QAM_ampa_256 = simde_mm256_set1_epi16(QAM64_n1);
|
||||
QAM_ampb_256 = simde_mm256_set1_epi16(QAM64_n2);
|
||||
} else if (mod_order == 8) {
|
||||
QAM_ampa_256 = simde_mm256_set1_epi16(QAM256_n1);
|
||||
QAM_ampb_256 = simde_mm256_set1_epi16(QAM256_n2);
|
||||
QAM_ampc_256 = simde_mm256_set1_epi16(QAM256_n3);
|
||||
}
|
||||
|
||||
for (int aatx = 0; aatx < nb_layers; aatx++) {
|
||||
simde__m256i *rxComp_256 = (simde__m256i *)&rxComp[aatx * nb_rx_ant][symbol * buffer_length];
|
||||
simde__m256i *ch_maga_256 = (simde__m256i *)ch_maga[aatx];
|
||||
simde__m256i *ch_magb_256 = (simde__m256i *)ch_magb[aatx];
|
||||
simde__m256i *ch_magc_256 = (simde__m256i *)ch_magc[aatx];
|
||||
|
||||
// First Rx antenna: direct store — eliminates need to pre memset the output buffers
|
||||
{
|
||||
simde__m256i *rxF_256 = (simde__m256i *)rxFext[0];
|
||||
simde__m256i *chF_256 = (simde__m256i *)chFext[aatx][0];
|
||||
|
||||
for (int i = 0; i < (int)(buffer_length >> 3); i++) {
|
||||
rxComp_256[i] = oai_mm256_cpx_mult_conj(chF_256[i], rxF_256[i], output_shift);
|
||||
|
||||
if (mod_order > 2) {
|
||||
simde__m256i mag = oai_mm256_smadd(chF_256[i], chF_256[i], output_shift);
|
||||
mag = simde_mm256_packs_epi32(mag, mag);
|
||||
mag = simde_mm256_unpacklo_epi16(mag, mag);
|
||||
ch_maga_256[i] = simde_mm256_mulhrs_epi16(mag, QAM_ampa_256);
|
||||
|
||||
if (mod_order > 4)
|
||||
ch_magb_256[i] = simde_mm256_mulhrs_epi16(mag, QAM_ampb_256);
|
||||
|
||||
if (mod_order > 6)
|
||||
ch_magc_256[i] = simde_mm256_mulhrs_epi16(mag, QAM_ampc_256);
|
||||
}
|
||||
}
|
||||
|
||||
if (rho) {
|
||||
for (int atx = 0; atx < nb_layers; atx++) {
|
||||
simde__m256i *rho_256 = (simde__m256i *)rho[aatx][atx];
|
||||
simde__m256i *chF2_256 = (simde__m256i *)chFext[atx][0];
|
||||
for (int i = 0; i < (int)(buffer_length >> 3); i++)
|
||||
rho_256[i] = oai_mm256_cpx_mult_conj(chF_256[i], chF2_256[i], output_shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remaining Rx antennas: accumulate (MRC)
|
||||
for (int aarx = 1; aarx < nb_rx_ant; aarx++) {
|
||||
simde__m256i *rxF_256 = (simde__m256i *)rxFext[aarx];
|
||||
simde__m256i *chF_256 = (simde__m256i *)chFext[aatx][aarx];
|
||||
|
||||
for (int i = 0; i < (int)(buffer_length >> 3); i++) {
|
||||
simde__m256i comp = oai_mm256_cpx_mult_conj(chF_256[i], rxF_256[i], output_shift);
|
||||
rxComp_256[i] = simde_mm256_add_epi16(rxComp_256[i], comp);
|
||||
|
||||
if (mod_order > 2) {
|
||||
simde__m256i mag = oai_mm256_smadd(chF_256[i], chF_256[i], output_shift);
|
||||
mag = simde_mm256_packs_epi32(mag, mag);
|
||||
mag = simde_mm256_unpacklo_epi16(mag, mag);
|
||||
ch_maga_256[i] = simde_mm256_add_epi16(ch_maga_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampa_256));
|
||||
|
||||
if (mod_order > 4)
|
||||
ch_magb_256[i] = simde_mm256_add_epi16(ch_magb_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampb_256));
|
||||
|
||||
if (mod_order > 6)
|
||||
ch_magc_256[i] = simde_mm256_add_epi16(ch_magc_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampc_256));
|
||||
}
|
||||
}
|
||||
|
||||
if (rho) {
|
||||
for (int atx = 0; atx < nb_layers; atx++) {
|
||||
simde__m256i *rho_256 = (simde__m256i *)rho[aatx][atx];
|
||||
simde__m256i *chF2_256 = (simde__m256i *)chFext[atx][aarx];
|
||||
for (int i = 0; i < (int)(buffer_length >> 3); i++)
|
||||
rho_256[i] = simde_mm256_adds_epi16(rho_256[i], oai_mm256_cpx_mult_conj(chF_256[i], chF2_256[i], output_shift));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2391
openair1/PHY/nr_phy_common/src/nr_compute_llr.c
Normal file
2391
openair1/PHY/nr_phy_common/src/nr_compute_llr.c
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user