Merge remote-tracking branch 'origin/srs_phy_simulator' into integration_2026_w03 (!3718)
Introduce SRS physical simulator and improvements This MR consists of two parts: - Introduces SRS physical simulator to test different configurations of SRS - Improvements in the SRS channel estimation (Addressing the comments from old, unfinished MR !2875) - rewrite nr_srs_channel_estimation() to loop over rx antennas and antenna ports to be able to parallelize - Improvements in timing_advance_offset and timing_advance_offset_nsec computation - Introduce SRS multi-symbol channel estimation - The channel impulse response is estimated from the averaged channel frequency response over multiple symbols - The channel frequency estimates are left as they are to be able to estimate doppler in the future - Simplify SRS channel estimation to handle memory alignment in the case of different SRS configurations (eg: comboffset) To use multiple symbols when running gNB, the following parameters needs to be edited in the function get_srs_resource() - srs_res->resourceMapping.startPosition with a range from {0,1,..,5} corresponds to the start symbol {13, 12, .. 8} with in a slot - srs_res->resourceMapping.nrofSymbols indicates the number of symbols {n1, n2, and n4} Make sure the that start symbol + number of symbols is < 14 The timing results for SRS in develop and srs_phy_simulator are as follows: Command used: sudo ./nr_ulsim -n1000 -s50 -S50 -R273 -W2 -y2 -z2 -E 1 -P develop |__ RX SRS time 124.94 us (1000 trials) (124.94 total [ms]) |__ Generate SRS sequence time 0.05 us (1000 trials) ( 0.05 total [ms]) |__ Get SRS signal time 19.41 us (1000 trials) ( 19.41 total [ms]) |__ SRS channel estimation time 89.11 us (1000 trials) ( 89.11 total [ms]) |__ SRS timing advance estimation time 13.10 us (1000 trials) ( 13.10 total [ms]) |__ SRS report TLV build time 2.80 us (1000 trials) ( 2.80 total [ms]) |__ SRS beam report build time 0.00 us ( 0 trials) |__ SRS IQ matrix build time 2.73 us (1000 trials) srs_phy_simulator |__ RX SRS time 211.93 us (1000 trials) (211.93 total [ms]) |__ Generate SRS sequence time 0.04 us (1000 trials) ( 0.04 total [ms]) |__ Get SRS signal time 19.55 us (1000 trials) ( 19.55 total [ms]) |__ SRS channel estimation time 152.05 us (1000 trials) (152.05 total [ms]) |__ SRS timing advance estimation time 36.67 us (1000 trials) ( 36.67 total [ms]) |__ SRS report TLV build time 2.96 us (1000 trials) ( 2.96 total [ms]) |__ SRS beam report build time 0.00 us ( 0 trials) |__ SRS IQ matrix build time 2.88 us (1000 trials) Note that in srs_phy_simulator, to compute timing offset ns, an oversampling factor of 2 is performed. Also, for peak detection, we average the channel estimates for every port.
This commit is contained in:
+23
-20
@@ -295,8 +295,8 @@ void nr_phy_config_request_sim(PHY_VARS_gNB *gNB,
|
||||
{
|
||||
NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
|
||||
nfapi_nr_config_request_scf_t *gNB_config = &gNB->gNB_config;
|
||||
//overwrite for new NR parameters
|
||||
|
||||
// overwrite with new NR parameters
|
||||
uint64_t rev_burst=0;
|
||||
for (int i=0; i<64; i++)
|
||||
rev_burst |= (((position_in_burst>>(63-i))&0x01)<<i);
|
||||
@@ -314,27 +314,30 @@ void nr_phy_config_request_sim(PHY_VARS_gNB *gNB,
|
||||
gNB_config->carrier_config.num_tx_ant.value = fp->nb_antennas_tx;
|
||||
gNB_config->carrier_config.num_rx_ant.value = fp->nb_antennas_rx;
|
||||
|
||||
gNB_config->tdd_table.tdd_period.value = 0;
|
||||
//gNB_config->subframe_config.dl_cyclic_prefix_type.value = (fp->Ncp == NORMAL) ? NFAPI_CP_NORMAL : NFAPI_CP_EXTENDED;
|
||||
|
||||
if (mu==0) {
|
||||
fp->dl_CarrierFreq = 2600000000;//from_nrarfcn(gNB_config->nfapi_config.rf_bands.rf_band[0],gNB_config->nfapi_config.nrarfcn.value);
|
||||
fp->ul_CarrierFreq = 2600000000;//fp->dl_CarrierFreq - (get_uldl_offset(gNB_config->nfapi_config.rf_bands.rf_band[0])*100000);
|
||||
fp->nr_band = 38;
|
||||
// fp->threequarter_fs= 0;
|
||||
} else if (mu==1) {
|
||||
fp->dl_CarrierFreq = 3600000000;//from_nrarfcn(gNB_config->nfapi_config.rf_bands.rf_band[0],gNB_config->nfapi_config.nrarfcn.value);
|
||||
fp->ul_CarrierFreq = 3600000000;//fp->dl_CarrierFreq - (get_uldl_offset(gNB_config->nfapi_config.rf_bands.rf_band[0])*100000);
|
||||
fp->nr_band = 78;
|
||||
// fp->threequarter_fs= 0;
|
||||
} else if (mu==3) {
|
||||
fp->dl_CarrierFreq = 27524520000;//from_nrarfcn(gNB_config->nfapi_config.rf_bands.rf_band[0],gNB_config->nfapi_config.nrarfcn.value);
|
||||
fp->ul_CarrierFreq = 27524520000;//fp->dl_CarrierFreq - (get_uldl_offset(gNB_config->nfapi_config.rf_bands.rf_band[0])*100000);
|
||||
fp->nr_band = 261;
|
||||
// fp->threequarter_fs= 0;
|
||||
switch (mu) {
|
||||
case 0:
|
||||
gNB->gNB_config.tdd_table.tdd_period.value = 7;
|
||||
fp->dl_CarrierFreq = 2600000000;
|
||||
fp->ul_CarrierFreq = 2600000000;
|
||||
fp->nr_band = 38;
|
||||
break;
|
||||
case 1:
|
||||
gNB->gNB_config.tdd_table.tdd_period.value = 6;
|
||||
fp->dl_CarrierFreq = 3600000000;
|
||||
fp->ul_CarrierFreq = 3600000000;
|
||||
fp->nr_band = 78;
|
||||
break;
|
||||
case 3:
|
||||
gNB->gNB_config.tdd_table.tdd_period.value = 3;
|
||||
fp->dl_CarrierFreq = 27524520000;
|
||||
fp->ul_CarrierFreq = 27524520000;
|
||||
fp->nr_band = 261;
|
||||
break;
|
||||
default:
|
||||
printf("unsupported numerology %d\n", mu);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fp->threequarter_fs = 0;
|
||||
frequency_range_t frequency_range = get_freq_range_from_band(fp->nr_band);
|
||||
int bw_index = get_supported_band_index(mu, frequency_range, N_RB_DL);
|
||||
gNB_config->carrier_config.dl_bandwidth.value = get_supported_bw_mhz(frequency_range, bw_index);
|
||||
|
||||
@@ -78,7 +78,7 @@ void nr_ue_layer_mapping(const c16_t *mod_symbs, const int n_layers, const int n
|
||||
\param sample_offset offset within rxdata (points to beginning of subframe)
|
||||
*/
|
||||
|
||||
int nr_slot_fep_ul(NR_DL_FRAME_PARMS *frame_parms,
|
||||
int nr_slot_fep_ul(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
int32_t *rxdata,
|
||||
int32_t *rxdataF,
|
||||
unsigned char symbol,
|
||||
@@ -111,6 +111,15 @@ void apply_nr_rotation_TX(const NR_DL_FRAME_PARMS *fp,
|
||||
int first_symbol,
|
||||
int nsymb);
|
||||
|
||||
void nr_ofdm_demod_and_rx_rotation(c16_t **rxdata,
|
||||
c16_t **rxdataF,
|
||||
const NR_DL_FRAME_PARMS *fp,
|
||||
int nb_antennas,
|
||||
int slot,
|
||||
int slot_offsetF,
|
||||
enum nr_Link linktype,
|
||||
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT]);
|
||||
|
||||
void perform_symbol_rotation(NR_DL_FRAME_PARMS *fp, double f0, c16_t *symbol_rotation);
|
||||
|
||||
void init_symbol_rotation(NR_DL_FRAME_PARMS *fp);
|
||||
|
||||
@@ -326,4 +326,3 @@ void apply_nr_rotation_TX(const NR_DL_FRAME_PARMS *fp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nr_slot_fep_ul(NR_DL_FRAME_PARMS *frame_parms,
|
||||
int nr_slot_fep_ul(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
int32_t *rxdata,
|
||||
int32_t *rxdataF,
|
||||
unsigned char symbol,
|
||||
@@ -237,3 +237,27 @@ void apply_nr_rotation_symbol_RX(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
15);
|
||||
}
|
||||
}
|
||||
|
||||
void nr_ofdm_demod_and_rx_rotation(c16_t **rxdata,
|
||||
c16_t **rxdataF,
|
||||
const NR_DL_FRAME_PARMS *fp,
|
||||
int nb_antennas,
|
||||
int slot,
|
||||
int slot_offsetF,
|
||||
enum nr_Link linktype,
|
||||
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT])
|
||||
{
|
||||
for (int aa = 0; aa < nb_antennas; aa++) {
|
||||
for (uint8_t symbol = 0; symbol < fp->symbols_per_slot; symbol++) {
|
||||
if (was_symbol_used[symbol] == true) {
|
||||
nr_slot_fep_ul(fp, (int32_t *)&rxdata[aa][0], (int32_t *)&rxdataF[aa][slot_offsetF], symbol, slot, 0);
|
||||
apply_nr_rotation_symbol_RX(fp,
|
||||
&rxdataF[aa][slot_offsetF + symbol * fp->ofdm_symbol_size],
|
||||
fp->symbol_rotation[linktype],
|
||||
fp->N_RB_UL,
|
||||
slot,
|
||||
symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,49 +36,73 @@
|
||||
|
||||
#define I0_SKIP_DC 1
|
||||
|
||||
int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const c16_t srs_estimated_channel_time[][frame_parms->ofdm_symbol_size])
|
||||
void nr_est_srs_timing_advance_offset(uint16_t ofdm_symbol_size,
|
||||
const c16_t srs_estimated_channel_time[][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size],
|
||||
uint8_t ant,
|
||||
uint8_t N_ap,
|
||||
uint32_t samples_per_frame,
|
||||
uint16_t *ta_offset,
|
||||
int16_t *ta_offset_nsec)
|
||||
{
|
||||
int timing_advance = 0;
|
||||
int max_val = 0;
|
||||
|
||||
for (int i = 0; i < frame_parms->ofdm_symbol_size; i++) {
|
||||
int temp = 0;
|
||||
for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) {
|
||||
int Re = ((c16_t*)srs_estimated_channel_time[aa])[i].r;
|
||||
int Im = ((c16_t*)srs_estimated_channel_time[aa])[i].i;
|
||||
temp += (Re*Re/2) + (Im*Im/2);
|
||||
int64_t mean_val = 0;
|
||||
int64_t max_val = 0;
|
||||
int32_t max_idx = 0;
|
||||
int16_t srs_toa = 0;
|
||||
int16_t ofdm_os_size = NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size;
|
||||
for (int k = 0; k < ofdm_os_size; k++) {
|
||||
int64_t abs_val = 0;
|
||||
for (int p_index = 0; p_index < N_ap; p_index++) {
|
||||
abs_val += squaredMod(srs_estimated_channel_time[p_index][k]);
|
||||
}
|
||||
if (temp > max_val) {
|
||||
timing_advance = i;
|
||||
max_val = temp;
|
||||
mean_val += abs_val;
|
||||
if (abs_val > max_val) {
|
||||
max_val = abs_val;
|
||||
max_idx = k;
|
||||
}
|
||||
}
|
||||
max_val = max_val / N_ap;
|
||||
mean_val = mean_val / (N_ap * ofdm_os_size);
|
||||
|
||||
if (timing_advance > frame_parms->ofdm_symbol_size/2) {
|
||||
timing_advance = timing_advance - frame_parms->ofdm_symbol_size;
|
||||
}
|
||||
if (max_idx > ofdm_os_size >> 1)
|
||||
max_idx = max_idx - ofdm_os_size;
|
||||
|
||||
// Scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size
|
||||
const uint16_t bw_scaling = frame_parms->ofdm_symbol_size >> 7;
|
||||
// Check for detection threshold
|
||||
if ((mean_val != 0) && (max_val / mean_val > NR_SRS_DETECTION_THRESHOLD)) {
|
||||
srs_toa = max_idx / NR_SRS_IDFT_OVERSAMP_FACTOR;
|
||||
|
||||
// do some integer rounding to improve TA accuracy
|
||||
int sync_pos_rounded;
|
||||
if (timing_advance > 0) {
|
||||
sync_pos_rounded = timing_advance + (bw_scaling >> 1) - 1;
|
||||
// restrict the computation of ta_offset to antenna 0
|
||||
if (ant == 0) {
|
||||
// Scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size
|
||||
const uint16_t bw_scaling = ofdm_symbol_size >> 7;
|
||||
|
||||
// do some integer rounding to improve TA accuracy
|
||||
int sync_pos_rounded;
|
||||
if (srs_toa > 0) {
|
||||
sync_pos_rounded = srs_toa + (bw_scaling >> 1) - 1;
|
||||
} else {
|
||||
sync_pos_rounded = srs_toa - (bw_scaling >> 1) + 1;
|
||||
}
|
||||
|
||||
*ta_offset = sync_pos_rounded / bw_scaling;
|
||||
|
||||
// put timing advance command in 0..63 range
|
||||
*ta_offset = BOUNDED_EVAL(0, *ta_offset + 31, 63);
|
||||
}
|
||||
*ta_offset_nsec = (max_idx * 1e9) / (NR_SRS_IDFT_OVERSAMP_FACTOR * samples_per_frame * 100);
|
||||
} else {
|
||||
sync_pos_rounded = timing_advance - (bw_scaling >> 1) + 1;
|
||||
*ta_offset = 0xFFFF;
|
||||
*ta_offset_nsec = 0x8000;
|
||||
}
|
||||
|
||||
int timing_advance_update = sync_pos_rounded / bw_scaling;
|
||||
|
||||
// put timing advance command in 0..63 range
|
||||
timing_advance_update += 31;
|
||||
|
||||
if (timing_advance_update < 0) timing_advance_update = 0;
|
||||
if (timing_advance_update > 63) timing_advance_update = 63;
|
||||
|
||||
return timing_advance_update;
|
||||
LOG_D(NR_PHY,
|
||||
"SRS estimatd ToA %d [RX ant %d]: TA offset %d, TA offset ns %d (max_val %ld, mean_val %ld, max_idx %d)\n",
|
||||
srs_toa,
|
||||
ant,
|
||||
*ta_offset,
|
||||
*ta_offset_nsec,
|
||||
max_val,
|
||||
mean_val,
|
||||
max_idx);
|
||||
}
|
||||
|
||||
void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB) {
|
||||
|
||||
@@ -769,28 +769,29 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB,
|
||||
} // Antenna loop
|
||||
}
|
||||
|
||||
int nr_srs_channel_estimation(
|
||||
const PHY_VARS_gNB *gNB,
|
||||
const int frame,
|
||||
const int slot,
|
||||
const nfapi_nr_srs_pdu_t *srs_pdu,
|
||||
const nr_srs_info_t *nr_srs_info,
|
||||
const c16_t **srs_generated_signal,
|
||||
c16_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)],
|
||||
c16_t srs_received_noise[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)],
|
||||
c16_t srs_estimated_channel_freq[][1 << srs_pdu->num_ant_ports]
|
||||
[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)],
|
||||
c16_t srs_estimated_channel_time[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size],
|
||||
c16_t srs_estimated_channel_time_shifted[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size],
|
||||
int16_t *snr_per_rb,
|
||||
int8_t *snr)
|
||||
int nr_srs_channel_estimation(int ant,
|
||||
int p_index,
|
||||
uint16_t ofdm_symbol_size,
|
||||
uint16_t first_carrier_offset,
|
||||
uint8_t N_symb_SRS,
|
||||
const nfapi_nr_srs_pdu_t *srs_pdu,
|
||||
const nr_srs_info_t *nr_srs_info,
|
||||
const c16_t *srs_generated_signal,
|
||||
c16_t srs_received_signal[ofdm_symbol_size * N_symb_SRS],
|
||||
c16_t srs_received_noise[ofdm_symbol_size * N_symb_SRS],
|
||||
c16_t srs_estimated_channel_freq[ofdm_symbol_size * N_symb_SRS],
|
||||
c16_t srs_estimated_channel_time[NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size],
|
||||
c16_t srs_estimated_channel_time_shifted[NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size],
|
||||
uint32_t *signal_power,
|
||||
uint32_t *noise_power,
|
||||
int16_t *noise_power_per_rb)
|
||||
{
|
||||
#ifdef SRS_DEBUG
|
||||
LOG_I(NR_PHY, "Calling %s function\n", __FUNCTION__);
|
||||
#endif
|
||||
|
||||
const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
|
||||
const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start * NR_NB_SC_PER_RB;
|
||||
const uint64_t subcarrier_offset = first_carrier_offset + srs_pdu->bwp_start * NR_NB_SC_PER_RB;
|
||||
const uint64_t first_subcarrier = (first_carrier_offset - (ofdm_symbol_size >> 1)) + srs_pdu->bwp_start * NR_NB_SC_PER_RB;
|
||||
|
||||
const uint8_t N_ap = 1 << srs_pdu->num_ant_ports;
|
||||
const uint8_t K_TC = 2 << srs_pdu->comb_size;
|
||||
@@ -800,249 +801,268 @@ int nr_srs_channel_estimation(
|
||||
if (N_ap == 4 && ((K_TC == 2 && srs_pdu->cyclic_shift >= 4) || (K_TC == 4 && srs_pdu->cyclic_shift >= 6))) {
|
||||
fd_cdm = 2;
|
||||
}
|
||||
uint16_t subcarrier;
|
||||
|
||||
c16_t srs_ls_estimated_channel[frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols)];
|
||||
uint8_t mem_offset = ((16 - ((intptr_t)&srs_estimated_channel_freq[0][0][subcarrier_offset + nr_srs_info->k_0_p[0][0]])) & 0xF)
|
||||
>> 2; // >> 2 <=> /sizeof(int32_t)
|
||||
c16_t srs_ls_estimated_channel[ofdm_symbol_size * N_symb_SRS];
|
||||
c16_t srs_estimated_channel_freq_avg[ofdm_symbol_size];
|
||||
memset(srs_ls_estimated_channel, 0, ofdm_symbol_size * N_symb_SRS * sizeof(c16_t));
|
||||
memset(srs_estimated_channel_freq_avg, 0, ofdm_symbol_size * sizeof(c16_t));
|
||||
|
||||
// filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0}
|
||||
// The End of OFDM symbol corresponds to the position of last 16384 in the filter
|
||||
// The c16multaddVectRealComplex applies the remaining 8 zeros of filter, therefore, to avoid a buffer overflow,
|
||||
// we added 8 in the array size
|
||||
c16_t srs_est[frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols) + mem_offset + 8] __attribute__((aligned(32)));
|
||||
c16_t ls_estimated = {0};
|
||||
for (int srs_symb = 0; srs_symb < N_symb_SRS; srs_symb++) {
|
||||
uint16_t srs_symbol_offset = srs_symb * ofdm_symbol_size;
|
||||
|
||||
for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) {
|
||||
for (int p_index = 0; p_index < N_ap; p_index++) {
|
||||
memset(srs_ls_estimated_channel, 0, frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols) * sizeof(c16_t));
|
||||
memset(srs_est, 0, (frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols) + mem_offset) * sizeof(c16_t));
|
||||
// Additional 4 in the array size is needed to maintain 16 byte memory alignment required for AVX2 instructions in channel
|
||||
// interpolation
|
||||
c16_t srs_est[ofdm_symbol_size + 4] __attribute__((aligned(32)));
|
||||
memset(srs_est, 0, (ofdm_symbol_size + 4) * sizeof(c16_t));
|
||||
|
||||
// Estimate 16 byte memory alignment offset for the first SRS subcarrier to use AVX2 instructions in channel interpolation
|
||||
uint8_t mem_offset = (16 - (((intptr_t)&srs_est[first_subcarrier + nr_srs_info->k_0_p[p_index][srs_symb]]) & 0xF))
|
||||
>> 2; // >> 2 <=> /sizeof(int32_t)
|
||||
|
||||
c16_t ls_estimated = {0};
|
||||
|
||||
#ifdef SRS_DEBUG
|
||||
LOG_I(NR_PHY, "====================== UE port %d --> gNB Rx antenna %i ======================\n", p_index, ant);
|
||||
LOG_I(NR_PHY, "====================== UE port %d --> gNB Rx antenna %i ======================\n", p_index, ant);
|
||||
LOG_I(NR_PHY, "============================== SRS symbol index %d ===========================\n", srs_symb);
|
||||
#endif
|
||||
|
||||
uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
|
||||
if (subcarrier >= frame_parms->ofdm_symbol_size) {
|
||||
subcarrier -= frame_parms->ofdm_symbol_size;
|
||||
}
|
||||
|
||||
c16_t *srs_estimated_channel16 = &srs_est[subcarrier + mem_offset];
|
||||
|
||||
for (int k = 0; k < M_sc_b_SRS; k++) {
|
||||
if (k % fd_cdm == 0) {
|
||||
ls_estimated = (c16_t){0, 0};
|
||||
uint16_t subcarrier_cdm = subcarrier;
|
||||
|
||||
for (int cdm_idx = 0; cdm_idx < fd_cdm; cdm_idx++) {
|
||||
c16_t generated_srs = srs_generated_signal[p_index][subcarrier_cdm];
|
||||
c16_t received_srs = srs_received_signal[ant][subcarrier_cdm];
|
||||
// We know that nr_srs_info->srs_generated_signal_bits bits are enough to represent the real and imaginary parts of
|
||||
// generated_srs. So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16
|
||||
// bits.
|
||||
ls_estimated = c16maddConjShift(generated_srs, received_srs, ls_estimated, nr_srs_info->srs_generated_signal_bits);
|
||||
|
||||
// Subcarrier increment
|
||||
subcarrier_cdm += K_TC;
|
||||
if (subcarrier_cdm >= frame_parms->ofdm_symbol_size) {
|
||||
subcarrier_cdm = subcarrier_cdm - frame_parms->ofdm_symbol_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
srs_ls_estimated_channel[subcarrier] = ls_estimated;
|
||||
|
||||
#ifdef SRS_DEBUG
|
||||
int subcarrier_log = subcarrier - subcarrier_offset;
|
||||
if (subcarrier_log < 0) {
|
||||
subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size;
|
||||
}
|
||||
if (subcarrier_log % 12 == 0) {
|
||||
LOG_I(NR_PHY, "------------------------------------ %d ------------------------------------\n", subcarrier_log / 12);
|
||||
LOG_I(NR_PHY, "\t __genRe________genIm__|____rxRe_________rxIm__|____lsRe________lsIm_\n");
|
||||
}
|
||||
LOG_I(NR_PHY,
|
||||
"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
|
||||
subcarrier_log,
|
||||
srs_generated_signal[p_index][subcarrier].r,
|
||||
srs_generated_signal[p_index][subcarrier].i,
|
||||
srs_received_signal[ant][subcarrier].r,
|
||||
srs_received_signal[ant][subcarrier].i,
|
||||
ls_estimated.r,
|
||||
ls_estimated.i);
|
||||
#endif
|
||||
|
||||
const uint16_t sc_offset = subcarrier + mem_offset;
|
||||
|
||||
// Channel interpolation
|
||||
if (srs_pdu->comb_size == 0) {
|
||||
if (k == 0) { // First subcarrier case
|
||||
// filt8_start is {12288,8192,4096,0,0,0,0,0}
|
||||
c16multaddVectRealComplex(filt8_start, &ls_estimated, srs_estimated_channel16, 8);
|
||||
} else if (subcarrier < K_TC) { // Start of OFDM symbol case
|
||||
// filt8_start is {12288,8192,4096,0,0,0,0,0}
|
||||
srs_estimated_channel16 = &srs_est[subcarrier];
|
||||
const short *filter = mem_offset == 0 ? filt8_start : filt8_start_shift2;
|
||||
c16multaddVectRealComplex(filter, &ls_estimated, srs_estimated_channel16, 8);
|
||||
} else if ((subcarrier + K_TC) >= frame_parms->ofdm_symbol_size
|
||||
|| k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases
|
||||
// filt8_end is {4096,8192,12288,16384,0,0,0,0}
|
||||
const short *filter = mem_offset == 0 || k == (M_sc_b_SRS - 1) ? filt8_end : filt8_end_shift2;
|
||||
c16multaddVectRealComplex(filter, &ls_estimated, srs_estimated_channel16, 8);
|
||||
} else if (k % 2 == 1) { // 1st middle case
|
||||
// filt8_middle2 is {4096,8192,8192,8192,4096,0,0,0}
|
||||
c16multaddVectRealComplex(filt8_middle2, &ls_estimated, srs_estimated_channel16, 8);
|
||||
} else if (k % 2 == 0) { // 2nd middle case
|
||||
// filt8_middle4 is {0,0,4096,8192,8192,8192,4096,0}
|
||||
c16multaddVectRealComplex(filt8_middle4, &ls_estimated, srs_estimated_channel16, 8);
|
||||
srs_estimated_channel16 = &srs_est[sc_offset];
|
||||
}
|
||||
} else {
|
||||
if (k == 0) { // First subcarrier case
|
||||
// filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0}
|
||||
c16multaddVectRealComplex(filt16_start, &ls_estimated, srs_estimated_channel16, 16);
|
||||
} else if (subcarrier < K_TC) { // Start of OFDM symbol case
|
||||
srs_estimated_channel16 = &srs_est[sc_offset];
|
||||
// filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0}
|
||||
c16multaddVectRealComplex(filt16_start, &ls_estimated, srs_estimated_channel16, 16);
|
||||
} else if ((subcarrier + K_TC) >= frame_parms->ofdm_symbol_size
|
||||
|| k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases
|
||||
// filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0}
|
||||
c16multaddVectRealComplex(filt16_end, &ls_estimated, srs_estimated_channel16, 16);
|
||||
} else { // Middle case
|
||||
// filt16_middle4 is {4096,8192,8192,8192,8192,8192,8192,8192,4096,0,0,0,0,0,0,0}
|
||||
c16multaddVectRealComplex(filt16_middle4, &ls_estimated, srs_estimated_channel16, 16);
|
||||
srs_estimated_channel16 = &srs_est[sc_offset];
|
||||
}
|
||||
}
|
||||
|
||||
// Subcarrier increment
|
||||
subcarrier += K_TC;
|
||||
if (subcarrier >= frame_parms->ofdm_symbol_size) {
|
||||
subcarrier -= frame_parms->ofdm_symbol_size;
|
||||
}
|
||||
|
||||
} // for (int k = 0; k < M_sc_b_SRS; k++)
|
||||
|
||||
memcpy(srs_estimated_channel_freq[ant][p_index],
|
||||
&srs_est[mem_offset],
|
||||
(frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols)) * sizeof(c16_t));
|
||||
|
||||
#ifdef SRS_DEBUG
|
||||
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
|
||||
if (subcarrier >= frame_parms->ofdm_symbol_size) {
|
||||
subcarrier -= frame_parms->ofdm_symbol_size;
|
||||
}
|
||||
|
||||
for (int k = 0; k < K_TC * M_sc_b_SRS; k++) {
|
||||
int subcarrier_log = subcarrier - subcarrier_offset;
|
||||
if (subcarrier_log < 0) {
|
||||
subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size;
|
||||
}
|
||||
|
||||
if (subcarrier_log % 12 == 0) {
|
||||
LOG_I(NR_PHY, "------------------------------------- %d -------------------------------------\n", subcarrier_log / 12);
|
||||
LOG_I(NR_PHY, "\t __lsRe__________lsIm__|____intRe_______intIm__|____noiRe_______noiIm__\n");
|
||||
}
|
||||
|
||||
LOG_I(NR_PHY,
|
||||
"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
|
||||
subcarrier_log,
|
||||
srs_ls_estimated_channel[subcarrier].r,
|
||||
srs_ls_estimated_channel[subcarrier].i,
|
||||
srs_estimated_channel_freq[ant][p_index][subcarrier].r,
|
||||
srs_estimated_channel_freq[ant][p_index][subcarrier].i,
|
||||
srs_received_noise[ant][subcarrier].r,
|
||||
srs_received_noise[ant][subcarrier].i);
|
||||
|
||||
// Subcarrier increment
|
||||
subcarrier++;
|
||||
if (subcarrier >= frame_parms->ofdm_symbol_size) {
|
||||
subcarrier -= frame_parms->ofdm_symbol_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Convert to time domain
|
||||
freq2time(gNB->frame_parms.ofdm_symbol_size,
|
||||
(int16_t *)srs_estimated_channel_freq[ant][p_index],
|
||||
(int16_t *)srs_estimated_channel_time[ant][p_index]);
|
||||
|
||||
memcpy(srs_estimated_channel_time_shifted[ant][p_index],
|
||||
&srs_estimated_channel_time[ant][p_index][gNB->frame_parms.ofdm_symbol_size >> 1],
|
||||
(gNB->frame_parms.ofdm_symbol_size >> 1) * sizeof(c16_t));
|
||||
|
||||
memcpy(&srs_estimated_channel_time_shifted[ant][p_index][gNB->frame_parms.ofdm_symbol_size >> 1],
|
||||
srs_estimated_channel_time[ant][p_index],
|
||||
(gNB->frame_parms.ofdm_symbol_size >> 1) * sizeof(c16_t));
|
||||
|
||||
} // for (int p_index = 0; p_index < N_ap; p_index++)
|
||||
} // for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++)
|
||||
|
||||
// Compute wideband SNR
|
||||
int tot_subcarriers = m_SRS_b * NR_NB_SC_PER_RB;
|
||||
uint32_t signal_power = 0;
|
||||
uint32_t noise_power = 0;
|
||||
for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) {
|
||||
for (int p_index = 0; p_index < N_ap; p_index++) {
|
||||
uint16_t subcarrier0 = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
|
||||
if (subcarrier0 >= frame_parms->ofdm_symbol_size) {
|
||||
subcarrier0 -= frame_parms->ofdm_symbol_size;
|
||||
}
|
||||
if (subcarrier0 + tot_subcarriers < frame_parms->ofdm_symbol_size) {
|
||||
signal_power += signal_energy_nodc(&srs_estimated_channel_freq[ant][p_index][subcarrier0], tot_subcarriers);
|
||||
if (p_index == 0)
|
||||
noise_power += signal_energy_nodc(&srs_received_noise[ant][subcarrier0], tot_subcarriers);
|
||||
} else {
|
||||
int size1 = frame_parms->ofdm_symbol_size - subcarrier0;
|
||||
int size2 = tot_subcarriers - size1;
|
||||
uint64_t signal_power_p1 = signal_energy_nodc(&srs_estimated_channel_freq[ant][p_index][subcarrier0], size1) * size1;
|
||||
uint64_t signal_power_p2 = signal_energy_nodc(&srs_estimated_channel_freq[ant][p_index][0], size2) * size2;
|
||||
signal_power += (signal_power_p1 + signal_power_p2) / tot_subcarriers;
|
||||
if (p_index == 0) {
|
||||
uint64_t noise_power_p1 = signal_energy_nodc(&srs_received_noise[ant][subcarrier0], size1) * size1;
|
||||
uint64_t noise_power_p2 = signal_energy_nodc(&srs_received_noise[ant][0], size2) * size2;
|
||||
noise_power += (noise_power_p1 + noise_power_p2) / tot_subcarriers;
|
||||
}
|
||||
}
|
||||
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][srs_symb];
|
||||
if (subcarrier >= ofdm_symbol_size) {
|
||||
subcarrier -= ofdm_symbol_size;
|
||||
}
|
||||
|
||||
uint16_t subcarrier_abs = mem_offset + first_subcarrier + nr_srs_info->k_0_p[p_index][srs_symb];
|
||||
c16_t *srs_estimated_channel16 = &srs_est[subcarrier_abs];
|
||||
|
||||
for (int k = 0; k < M_sc_b_SRS; k++) {
|
||||
if (k % fd_cdm == 0) {
|
||||
ls_estimated = (c16_t){0, 0};
|
||||
uint16_t subcarrier_cdm = subcarrier;
|
||||
|
||||
for (int cdm_idx = 0; cdm_idx < fd_cdm; cdm_idx++) {
|
||||
c16_t generated_srs = srs_generated_signal[srs_symbol_offset + subcarrier_cdm];
|
||||
c16_t received_srs = srs_received_signal[srs_symbol_offset + subcarrier_cdm];
|
||||
// We know that nr_srs_info->srs_generated_signal_bits bits are enough to represent the real and imaginary parts of
|
||||
// generated_srs. So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16
|
||||
// bits.
|
||||
ls_estimated = c16maddConjShift(generated_srs, received_srs, ls_estimated, nr_srs_info->srs_generated_signal_bits);
|
||||
|
||||
// Subcarrier increment
|
||||
subcarrier_cdm += K_TC;
|
||||
if (subcarrier_cdm >= ofdm_symbol_size) {
|
||||
subcarrier_cdm = subcarrier_cdm - ofdm_symbol_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
srs_ls_estimated_channel[srs_symbol_offset + subcarrier] = ls_estimated;
|
||||
|
||||
#ifdef SRS_DEBUG
|
||||
int subcarrier_log = subcarrier - subcarrier_offset;
|
||||
if (subcarrier_log < 0) {
|
||||
subcarrier_log = subcarrier_log + ofdm_symbol_size;
|
||||
}
|
||||
if (subcarrier_log % 12 == 0) {
|
||||
LOG_I(NR_PHY, "------------------------------------ %d ------------------------------------\n", subcarrier_log / 12);
|
||||
LOG_I(NR_PHY, "\t __genRe________genIm__|____rxRe_________rxIm__|____lsRe________lsIm_\n");
|
||||
}
|
||||
LOG_I(NR_PHY,
|
||||
"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
|
||||
subcarrier_log,
|
||||
srs_generated_signal[srs_symbol_offset + subcarrier].r,
|
||||
srs_generated_signal[srs_symbol_offset + subcarrier].i,
|
||||
srs_received_signal[srs_symbol_offset + subcarrier].r,
|
||||
srs_received_signal[srs_symbol_offset + subcarrier].i,
|
||||
ls_estimated.r,
|
||||
ls_estimated.i);
|
||||
#endif
|
||||
|
||||
// Channel interpolation
|
||||
if (srs_pdu->comb_size == 0) {
|
||||
if (k == 0) { // First subcarrier case
|
||||
// filt8_start is {12288,8192,4096,0,0,0,0,0}
|
||||
c16multaddVectRealComplex(filt8_start, &ls_estimated, srs_estimated_channel16, 8);
|
||||
} else if (k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases
|
||||
// filt8_end is {4096,8192,12288,16384,0,0,0,0}
|
||||
c16multaddVectRealComplex(filt8_end, &ls_estimated, srs_estimated_channel16, 8);
|
||||
} else if (k % 2 == 1) { // 1st middle case
|
||||
// filt8_middle2 is {4096,8192,8192,8192,4096,0,0,0}
|
||||
c16multaddVectRealComplex(filt8_middle2, &ls_estimated, srs_estimated_channel16, 8);
|
||||
} else if (k % 2 == 0) { // 2nd middle case
|
||||
// filt8_middle4 is {0,0,4096,8192,8192,8192,4096,0}
|
||||
c16multaddVectRealComplex(filt8_middle4, &ls_estimated, srs_estimated_channel16, 8);
|
||||
srs_estimated_channel16 = &srs_est[subcarrier_abs];
|
||||
}
|
||||
} else {
|
||||
if (k == 0) { // First subcarrier case
|
||||
// filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0}
|
||||
c16multaddVectRealComplex(filt16_start, &ls_estimated, srs_estimated_channel16, 16);
|
||||
} else if (k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases
|
||||
// filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0}
|
||||
c16multaddVectRealComplex(filt16_end, &ls_estimated, srs_estimated_channel16, 16);
|
||||
} else { // Middle case
|
||||
// filt16_middle4 is {4096,8192,8192,8192,8192,8192,8192,8192,4096,0,0,0,0,0,0,0}
|
||||
c16multaddVectRealComplex(filt16_middle4, &ls_estimated, srs_estimated_channel16, 16);
|
||||
srs_estimated_channel16 = &srs_est[subcarrier_abs];
|
||||
}
|
||||
}
|
||||
|
||||
// Subcarrier increment
|
||||
subcarrier += K_TC;
|
||||
if (subcarrier >= ofdm_symbol_size) {
|
||||
subcarrier -= ofdm_symbol_size;
|
||||
}
|
||||
|
||||
subcarrier_abs += K_TC;
|
||||
|
||||
} // for (int k = 0; k < M_sc_b_SRS; k++)
|
||||
|
||||
memcpy(&srs_estimated_channel_freq[srs_symbol_offset], &srs_est[mem_offset], ofdm_symbol_size * sizeof(c16_t));
|
||||
|
||||
// Average srs channel estimates over multiple symbols
|
||||
int16_t scale_factor = (1 << 15) / N_symb_SRS;
|
||||
multadd_complex_vector_real_scalar(&srs_estimated_channel_freq[srs_symbol_offset],
|
||||
scale_factor,
|
||||
srs_estimated_channel_freq_avg,
|
||||
ofdm_symbol_size);
|
||||
|
||||
#ifdef SRS_DEBUG
|
||||
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][srs_symb];
|
||||
if (subcarrier >= ofdm_symbol_size) {
|
||||
subcarrier -= ofdm_symbol_size;
|
||||
}
|
||||
|
||||
subcarrier_abs = first_subcarrier + nr_srs_info->k_0_p[p_index][srs_symb];
|
||||
|
||||
for (int k = 0; k < K_TC * M_sc_b_SRS; k++) {
|
||||
int subcarrier_log = subcarrier - subcarrier_offset;
|
||||
if (subcarrier_log < 0) {
|
||||
subcarrier_log = subcarrier_log + ofdm_symbol_size;
|
||||
}
|
||||
|
||||
if (subcarrier_log % 12 == 0) {
|
||||
LOG_I(NR_PHY,
|
||||
"---------------------------- PRB %d, symbol %d -------------------------------\n",
|
||||
subcarrier_log / 12,
|
||||
srs_symb);
|
||||
LOG_I(NR_PHY, "\t __lsRe__________lsIm__|____intRe_______intIm__|____noiRe_______noiIm__\n");
|
||||
}
|
||||
|
||||
LOG_I(NR_PHY,
|
||||
"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
|
||||
subcarrier_log,
|
||||
srs_ls_estimated_channel[srs_symbol_offset + subcarrier].r,
|
||||
srs_ls_estimated_channel[srs_symbol_offset + subcarrier].i,
|
||||
srs_estimated_channel_freq[srs_symbol_offset + subcarrier_abs].r,
|
||||
srs_estimated_channel_freq[srs_symbol_offset + subcarrier_abs].i,
|
||||
srs_received_noise[srs_symbol_offset + subcarrier].r,
|
||||
srs_received_noise[srs_symbol_offset + subcarrier].i);
|
||||
|
||||
// Subcarrier increment
|
||||
subcarrier++;
|
||||
if (subcarrier >= ofdm_symbol_size) {
|
||||
subcarrier -= ofdm_symbol_size;
|
||||
}
|
||||
subcarrier_abs++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
signal_power = max(signal_power / (frame_parms->nb_antennas_rx * N_ap), 1);
|
||||
noise_power = max(noise_power / (frame_parms->nb_antennas_rx), 1);
|
||||
if (signal_power == 0) {
|
||||
|
||||
// Convert to time domain
|
||||
int16_t ofdm_symbol_size_half = ofdm_symbol_size >> 1;
|
||||
int16_t ofdm_os_size = NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size;
|
||||
int16_t ofdm_os_size_half = ofdm_os_size >> 1;
|
||||
int16_t start_offset = ofdm_os_size - ofdm_symbol_size_half;
|
||||
|
||||
c16_t chF_interpol[ofdm_os_size] __attribute__((aligned(32)));
|
||||
memset(chF_interpol, 0, sizeof(chF_interpol));
|
||||
|
||||
// Place SRS channel estimates in FFT shifted format for oversampling
|
||||
memcpy(&chF_interpol[0], &srs_estimated_channel_freq_avg[ofdm_symbol_size_half], ofdm_symbol_size_half * sizeof(c16_t));
|
||||
memcpy(&chF_interpol[start_offset], &srs_estimated_channel_freq_avg[0], ofdm_symbol_size_half * sizeof(c16_t));
|
||||
|
||||
// Convert to time domain oversampled
|
||||
freq2time(ofdm_os_size, (int16_t *)chF_interpol, (int16_t *)srs_estimated_channel_time);
|
||||
|
||||
// Do FFT shift
|
||||
memcpy(srs_estimated_channel_time_shifted, &srs_estimated_channel_time[ofdm_os_size_half], ofdm_os_size_half * sizeof(c16_t));
|
||||
|
||||
memcpy(&srs_estimated_channel_time_shifted[ofdm_os_size_half], srs_estimated_channel_time, ofdm_os_size_half * sizeof(c16_t));
|
||||
|
||||
// Compute wideband SNR on the symbol 0
|
||||
int tot_subcarriers = m_SRS_b * NR_NB_SC_PER_RB;
|
||||
|
||||
uint16_t subcarrier_abs = first_subcarrier + nr_srs_info->k_0_p[p_index][0];
|
||||
if (subcarrier_abs + tot_subcarriers < ofdm_symbol_size_half) {
|
||||
*signal_power = signal_energy_nodc(&srs_estimated_channel_freq[subcarrier_abs], tot_subcarriers) / tot_subcarriers;
|
||||
} else {
|
||||
int size1 = ofdm_symbol_size_half - subcarrier_abs;
|
||||
int size2 = tot_subcarriers - size1;
|
||||
uint64_t signal_power_p1 = signal_energy_nodc(&srs_estimated_channel_freq[subcarrier_abs], size1) * size1;
|
||||
uint64_t signal_power_p2 = signal_energy_nodc(&srs_estimated_channel_freq[ofdm_symbol_size_half], size2) * size2;
|
||||
*signal_power = (signal_power_p1 + signal_power_p2) / tot_subcarriers;
|
||||
}
|
||||
|
||||
if (*signal_power == 0) {
|
||||
LOG_W(NR_PHY, "Received SRS signal power is 0\n");
|
||||
return -1;
|
||||
}
|
||||
*snr = dB_fixed(signal_power) - dB_fixed(noise_power);
|
||||
|
||||
// Compute SNR per RB
|
||||
uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[0][0];
|
||||
for (int rb = 0; rb < m_SRS_b; rb++) {
|
||||
if (subcarrier >= frame_parms->ofdm_symbol_size) {
|
||||
subcarrier -= frame_parms->ofdm_symbol_size;
|
||||
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
|
||||
if (subcarrier >= ofdm_symbol_size) {
|
||||
subcarrier -= ofdm_symbol_size;
|
||||
}
|
||||
|
||||
if (p_index == 0) {
|
||||
if (subcarrier + tot_subcarriers < ofdm_symbol_size) {
|
||||
*noise_power = signal_energy_nodc(&srs_received_noise[subcarrier], tot_subcarriers) / tot_subcarriers;
|
||||
} else {
|
||||
int size1 = ofdm_symbol_size - subcarrier;
|
||||
int size2 = tot_subcarriers - size1;
|
||||
uint64_t noise_power_p1 = signal_energy_nodc(&srs_received_noise[subcarrier], size1) * size1;
|
||||
uint64_t noise_power_p2 = signal_energy_nodc(&srs_received_noise[0], size2) * size2;
|
||||
*noise_power = (noise_power_p1 + noise_power_p2) / tot_subcarriers;
|
||||
}
|
||||
uint32_t noise_power_per_rb = 0;
|
||||
for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) {
|
||||
if (subcarrier + NR_NB_SC_PER_RB < frame_parms->ofdm_symbol_size) {
|
||||
noise_power_per_rb += signal_energy_nodc(&srs_received_noise[ant][subcarrier], NR_NB_SC_PER_RB);
|
||||
} else {
|
||||
int size1 = frame_parms->ofdm_symbol_size - subcarrier;
|
||||
int size2 = NR_NB_SC_PER_RB - size1;
|
||||
uint32_t noise_power_per_rb1 = signal_energy_nodc(&srs_received_noise[ant][subcarrier], size1) * size1;
|
||||
uint32_t noise_power_per_rb2 = signal_energy_nodc(&srs_received_noise[ant][0], size2) * size2;
|
||||
noise_power_per_rb += (noise_power_per_rb1 + noise_power_per_rb2) / NR_NB_SC_PER_RB;
|
||||
}
|
||||
|
||||
// Compute SNR per RB for port 0 and symbol 0
|
||||
if (p_index == 0) {
|
||||
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
|
||||
for (int rb = 0; rb < m_SRS_b; rb++) {
|
||||
if (subcarrier >= ofdm_symbol_size) {
|
||||
subcarrier -= ofdm_symbol_size;
|
||||
}
|
||||
}
|
||||
noise_power_per_rb = max(noise_power_per_rb / (frame_parms->nb_antennas_rx), 1);
|
||||
snr_per_rb[rb] = dB_fixed(signal_power) - dB_fixed(noise_power_per_rb);
|
||||
subcarrier += NR_NB_SC_PER_RB;
|
||||
if (subcarrier + NR_NB_SC_PER_RB < ofdm_symbol_size) {
|
||||
noise_power_per_rb[rb] += signal_energy_nodc(&srs_received_noise[subcarrier], NR_NB_SC_PER_RB);
|
||||
} else {
|
||||
int size1 = ofdm_symbol_size - subcarrier;
|
||||
int size2 = NR_NB_SC_PER_RB - size1;
|
||||
uint32_t noise_power_per_rb1 = signal_energy_nodc(&srs_received_noise[subcarrier], size1) * size1;
|
||||
uint32_t noise_power_per_rb2 = signal_energy_nodc(&srs_received_noise[0], size2) * size2;
|
||||
noise_power_per_rb[rb] += (noise_power_per_rb1 + noise_power_per_rb2) / NR_NB_SC_PER_RB;
|
||||
}
|
||||
noise_power_per_rb[rb] = max(noise_power_per_rb[rb], 1);
|
||||
subcarrier += NR_NB_SC_PER_RB;
|
||||
|
||||
#ifdef SRS_DEBUG
|
||||
LOG_I(NR_PHY, "[RB %3i] noise_power_per_rb = %i, snr_per_rb = %i dB\n", rb, noise_power_per_rb, snr_per_rb[rb]);
|
||||
LOG_I(NR_PHY,
|
||||
"[RB %3i] noise_power_per_rb = %i, SNR_per_rb = %i dB\n",
|
||||
rb,
|
||||
noise_power_per_rb[rb],
|
||||
dB_fixed(*signal_power) - dB_fixed(noise_power_per_rb[rb]));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SRS_DEBUG
|
||||
LOG_I(NR_PHY, "signal_power = %i dB, noise_power = %i dB, SNR = %i dB\n", dB_fixed(signal_power), dB_fixed(noise_power), *snr);
|
||||
int32_t signal_power_dB = dB_fixed(*signal_power);
|
||||
int32_t noise_power_dB = dB_fixed(*noise_power);
|
||||
LOG_I(NR_PHY,
|
||||
"signal_power = %i dB, noise_power = %i dB, SNR = %i dB\n",
|
||||
signal_power_dB,
|
||||
noise_power_dB,
|
||||
signal_power_dB - noise_power_dB);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -59,8 +59,13 @@ void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB);
|
||||
|
||||
void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_symb, uint32_t rb_mask_ul[14][9]);
|
||||
|
||||
int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const c16_t srs_estimated_channel_time[][frame_parms->ofdm_symbol_size]);
|
||||
void nr_est_srs_timing_advance_offset(uint16_t ofdm_symbol_size,
|
||||
const c16_t srs_estimated_channel_time[][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size],
|
||||
uint8_t ant,
|
||||
uint8_t N_ap,
|
||||
uint32_t samples_per_frame,
|
||||
uint16_t *timing_advance_offset,
|
||||
int16_t *timing_advance_offset_nsec);
|
||||
|
||||
void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB,
|
||||
NR_DL_FRAME_PARMS *frame_parms,
|
||||
@@ -70,21 +75,22 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB,
|
||||
unsigned char symbol,
|
||||
uint32_t nb_re_pusch);
|
||||
|
||||
int nr_srs_channel_estimation(
|
||||
const PHY_VARS_gNB *gNB,
|
||||
const int frame,
|
||||
const int slot,
|
||||
const nfapi_nr_srs_pdu_t *srs_pdu,
|
||||
const nr_srs_info_t *nr_srs_info,
|
||||
const c16_t **srs_generated_signal,
|
||||
c16_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)],
|
||||
c16_t srs_received_noise[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)],
|
||||
c16_t srs_estimated_channel_freq[][1 << srs_pdu->num_ant_ports]
|
||||
[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)],
|
||||
c16_t srs_estimated_channel_time[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size],
|
||||
c16_t srs_estimated_channel_time_shifted[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size],
|
||||
int16_t *snr_per_rb,
|
||||
int8_t *snr);
|
||||
int nr_srs_channel_estimation(int ant,
|
||||
int p_index,
|
||||
uint16_t ofdm_symbol_size,
|
||||
uint16_t first_carrier_offset,
|
||||
uint8_t N_symb_SRS,
|
||||
const nfapi_nr_srs_pdu_t *srs_pdu,
|
||||
const nr_srs_info_t *nr_srs_info,
|
||||
const c16_t *srs_generated_signal,
|
||||
c16_t srs_received_signal[ofdm_symbol_size * N_symb_SRS],
|
||||
c16_t srs_received_noise[ofdm_symbol_size * N_symb_SRS],
|
||||
c16_t srs_estimated_channel_freq[ofdm_symbol_size * N_symb_SRS],
|
||||
c16_t srs_estimated_channel_time[NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size],
|
||||
c16_t srs_estimated_channel_time_shifted[NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size],
|
||||
uint32_t *signal_power,
|
||||
uint32_t *noise_power,
|
||||
int16_t *noise_power_per_rb);
|
||||
|
||||
void nr_freq_equalization(NR_DL_FRAME_PARMS *frame_parms,
|
||||
c16_t *rxdataF_comp,
|
||||
|
||||
@@ -231,6 +231,22 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB,
|
||||
c16_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)],
|
||||
c16_t srs_received_noise[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)]);
|
||||
|
||||
void nr_srs_rx_procedures(PHY_VARS_gNB *gNB,
|
||||
int frame_rx,
|
||||
int slot_rx,
|
||||
uint8_t nb_antennas_rx,
|
||||
uint8_t N_ap,
|
||||
uint8_t N_symb_SRS,
|
||||
uint16_t ofdm_symbol_size,
|
||||
NR_gNB_SRS_t *srs,
|
||||
nr_srs_info_t *nr_srs_info,
|
||||
int *srs_est,
|
||||
c16_t srs_estimated_channel_freq[][N_ap][ofdm_symbol_size * N_symb_SRS],
|
||||
c16_t srs_estimated_channel_time[][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size],
|
||||
int16_t *snr_per_rb,
|
||||
uint16_t *timing_advance_offset,
|
||||
int16_t *timing_advance_offset_nsec);
|
||||
|
||||
int get_nr_prach_duration(uint8_t prach_format);
|
||||
|
||||
void free_nr_prach_entry(prach_list_t *, prach_item_t *);
|
||||
|
||||
@@ -56,7 +56,8 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu
|
||||
srs->active = true;
|
||||
srs->beam_nb = 0;
|
||||
if (gNB->common_vars.beam_id) {
|
||||
int bitmap = SL_to_bitmap(srs_pdu->time_start_position, 1 << srs_pdu->num_symbols);
|
||||
const uint8_t l0 = gNB->frame_parms.symbols_per_slot - 1 - srs_pdu->time_start_position;
|
||||
int bitmap = SL_to_bitmap(l0, 1 << srs_pdu->num_symbols);
|
||||
int fapi_beam_idx = srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx;
|
||||
srs->beam_nb = beam_index_allocation(gNB->enable_analog_das,
|
||||
fapi_beam_idx,
|
||||
@@ -84,7 +85,7 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB,
|
||||
const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
|
||||
|
||||
const uint16_t n_symbols = (slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot; // number of symbols until this slot
|
||||
const uint8_t l0 = srs_pdu->time_start_position; // starting symbol in this slot
|
||||
const uint8_t l0 = frame_parms->symbols_per_slot - 1 - srs_pdu->time_start_position; // starting symbol in this slot
|
||||
const uint64_t symbol_offset = (n_symbols + l0) * frame_parms->ofdm_symbol_size;
|
||||
const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start * NR_NB_SC_PER_RB;
|
||||
|
||||
|
||||
@@ -168,15 +168,20 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
|
||||
/** \brief This function does IFFT for PUSCH
|
||||
*/
|
||||
|
||||
uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
|
||||
const uint8_t slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const uint8_t n_antenna_ports,
|
||||
c16_t **txdataF,
|
||||
c16_t **txdata,
|
||||
uint32_t linktype,
|
||||
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT],
|
||||
bool no_phase_pre_comp);
|
||||
uint8_t nr_tx_rotation_and_ofdm_mod(const uint8_t slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const uint8_t n_antenna_ports,
|
||||
c16_t **txdataF,
|
||||
c16_t **txdata,
|
||||
uint32_t linktype,
|
||||
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT],
|
||||
bool no_phase_pre_comp);
|
||||
|
||||
bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
c16_t **txdataF,
|
||||
nr_phy_data_tx_t *phy_data,
|
||||
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT]);
|
||||
|
||||
void clean_UE_harq(PHY_VARS_NR_UE *UE);
|
||||
|
||||
|
||||
@@ -1502,15 +1502,14 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
|
||||
stop_meas_nr_ue_phy(UE, PUSCH_PROC_STATS);
|
||||
}
|
||||
|
||||
uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
|
||||
const uint8_t slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const uint8_t n_antenna_ports,
|
||||
c16_t **txdataF,
|
||||
c16_t **txdata,
|
||||
uint32_t linktype,
|
||||
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT],
|
||||
bool no_phase_pre_comp)
|
||||
uint8_t nr_tx_rotation_and_ofdm_mod(const uint8_t slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const uint8_t n_antenna_ports,
|
||||
c16_t **txdataF,
|
||||
c16_t **txdata,
|
||||
uint32_t linktype,
|
||||
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT],
|
||||
bool no_phase_pre_comp)
|
||||
{
|
||||
int N_RB = (linktype == link_type_sl) ? frame_parms->N_RB_SL : frame_parms->N_RB_UL;
|
||||
|
||||
|
||||
@@ -180,3 +180,39 @@ int32_t interference_power(int32_t *input, uint32_t length)
|
||||
return temp;
|
||||
}
|
||||
|
||||
// Computes transmitter energy level
|
||||
double compute_tx_energy_level(c16_t **txdata, int nb_antennas, int offset, int length, int n_trials)
|
||||
{
|
||||
double txlev_sum = 0, atxlev[nb_antennas];
|
||||
for (int aa = 0; aa < nb_antennas; aa++) {
|
||||
atxlev[aa] = signal_energy((int32_t *)&txdata[aa][offset], length);
|
||||
|
||||
txlev_sum += atxlev[aa];
|
||||
|
||||
if (n_trials == 1)
|
||||
printf("txlev[%d] = %f (%f dB) txlev_sum %f\n", aa, atxlev[aa], 10 * log10(atxlev[aa]), txlev_sum);
|
||||
}
|
||||
return txlev_sum;
|
||||
}
|
||||
|
||||
// Computes noise variance from the input transmit energy and SNR
|
||||
double compute_noise_variance(double txlev_sum,
|
||||
uint16_t ofdm_symbol_size,
|
||||
int N_RB,
|
||||
uint8_t precod_nbr_layers,
|
||||
double SNR,
|
||||
int n_trials)
|
||||
{
|
||||
// Justification of division by precod_nbr_layers:
|
||||
// When the channel is the identity matrix, the results in terms of SNR should be almost equal for 2x2 and 4x4.
|
||||
double sigma_dB = 10 * log10(txlev_sum / precod_nbr_layers * ((double)ofdm_symbol_size / (12 * N_RB))) - SNR;
|
||||
double sigma = pow(10, sigma_dB / 10);
|
||||
|
||||
if (n_trials == 1)
|
||||
printf("sigma %f (%f dB), txlev_sum %f (factor %f)\n",
|
||||
sigma,
|
||||
sigma_dB,
|
||||
10 * log10(txlev_sum),
|
||||
(double)(double)ofdm_symbol_size / (12 * N_RB));
|
||||
return sigma;
|
||||
}
|
||||
|
||||
@@ -927,6 +927,14 @@ double signal_energy_fp(double *s_re[2], double *s_im[2], uint32_t nb_antennas,
|
||||
*/
|
||||
double signal_energy_fp2(struct complexd *s, uint32_t length);
|
||||
|
||||
double compute_tx_energy_level(c16_t **txdata, int nb_antennas, int offset, int length, int n_trials);
|
||||
|
||||
double compute_noise_variance(double txlev_sum,
|
||||
uint16_t ofdm_symbol_size,
|
||||
int N_RB,
|
||||
uint8_t precod_nbr_layers,
|
||||
double SNR,
|
||||
int n_trials);
|
||||
|
||||
int32_t iSqrt(int32_t value);
|
||||
uint8_t log2_approx(uint32_t);
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
|
||||
#define MAX_NUM_RU_PER_gNB 8
|
||||
#define MAX_PUCCH0_NID 8
|
||||
#define NR_SRS_IDFT_OVERSAMP_FACTOR 2
|
||||
#define NR_SRS_DETECTION_THRESHOLD 10
|
||||
|
||||
typedef struct {
|
||||
int nb_id;
|
||||
|
||||
@@ -372,7 +372,8 @@ bool generate_srs_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
nr_srs_info_t *nr_srs_info,
|
||||
int16_t amp,
|
||||
frame_t frame_number,
|
||||
slot_t slot_number);
|
||||
slot_t slot_number,
|
||||
uint8_t nb_antennas);
|
||||
void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const csi_mapping_parms_t *phy_csi_parms,
|
||||
const int16_t amp,
|
||||
|
||||
@@ -146,11 +146,12 @@ bool generate_srs_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
nr_srs_info_t *nr_srs_info,
|
||||
int16_t amp,
|
||||
frame_t frame_number,
|
||||
slot_t slot_number)
|
||||
slot_t slot_number,
|
||||
uint8_t nb_antennas)
|
||||
{
|
||||
uint8_t K_TC = 2 << nr_srs_info->comb_size;
|
||||
/* Number of antenna ports (M) can't be higher than number of physical antennas (N): M <= N */
|
||||
int N_ap = nr_srs_info->n_srs_ports > frame_parms->nb_antennas_tx ? frame_parms->nb_antennas_tx : nr_srs_info->n_srs_ports;
|
||||
int N_ap = nr_srs_info->n_srs_ports > nb_antennas ? nb_antennas : nr_srs_info->n_srs_ports;
|
||||
uint8_t l0 = frame_parms->symbols_per_slot - 1 - nr_srs_info->l_offset; // Starting symbol position in the time domain
|
||||
uint8_t n_SRS_cs_max = srs_max_number_cs[nr_srs_info->comb_size];
|
||||
int m_SRS_b = get_m_srs(nr_srs_info->C_SRS, nr_srs_info->B_SRS); // Number of resource blocks
|
||||
@@ -180,6 +181,11 @@ bool generate_srs_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
LOG_I(NR_PHY,"M_sc_b_SRS = %i\n", M_sc_b_SRS);
|
||||
#endif
|
||||
|
||||
AssertFatal(l0 + nr_srs_info->N_symb_SRS - 1 < frame_parms->symbols_per_slot,
|
||||
"last symbol index %d should be < %d\n",
|
||||
l0 + nr_srs_info->N_symb_SRS,
|
||||
frame_parms->symbols_per_slot - 1);
|
||||
|
||||
// Validation of SRS config parameters
|
||||
|
||||
if (nr_srs_info->R == 0) {
|
||||
|
||||
Reference in New Issue
Block a user