Files
openairinterface5g/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c
T
Bartosz Podrygajlo 0161a1c4fd Optimization for unused symbols in NR UE
After processing TX frequency domain data skip IFFT call for symbols that aren't
used, the time domain buffer is memset instead.
2025-04-04 11:12:48 +02:00

497 lines
19 KiB
C

/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/***********************************************************************
*
* FILENAME : srs_modulation_nr_nr.c
*
* MODULE :
*
* DESCRIPTION : function to set uplink reference symbols
* see TS 38211 6.4.1.4 Sounding reference signal
*
************************************************************************/
#include <stdio.h>
#include <math.h>
#include "PHY/impl_defs_nr.h"
#include "PHY/defs_nr_UE.h"
#include "PHY/NR_REFSIG/ss_pbch_nr.h"
#include "PHY/NR_REFSIG/dmrs_nr.h"
#include "PHY/NR_REFSIG/ul_ref_seq_nr.h"
#include "PHY/NR_UE_TRANSPORT/srs_modulation_nr.h"
//#define SRS_DEBUG
uint16_t group_number_hopping(int slot_number,
uint8_t n_ID_SRS,
uint8_t l0,
uint8_t l_line) {
// Pseudo-random sequence c(i) defined by TS 38.211 - Section 5.2.1
uint32_t cinit = n_ID_SRS;
uint8_t c_last_index = 8 * (slot_number * N_SYMB_SLOT + l0 + l_line) + 7;
uint32_t *c_sequence = calloc(c_last_index+1, sizeof(uint32_t));
pseudo_random_sequence(c_last_index+1, c_sequence, cinit);
// TS 38.211 - 6.4.1.4.2 Sequence generation
uint32_t f_gh = 0;
for (int m = 0; m <= 7; m++) {
f_gh += c_sequence[8 * (slot_number * N_SYMB_SLOT + l0 + l_line) + m] << m;
}
f_gh = f_gh%30;
uint8_t u = (f_gh + n_ID_SRS)%U_GROUP_NUMBER;
free(c_sequence);
return u;
}
uint16_t sequence_number_hopping(int slot_number,
uint8_t n_ID_SRS,
uint16_t M_sc_b_SRS,
uint8_t l0,
uint8_t l_line) {
uint16_t v = 0;
if (M_sc_b_SRS > 6 * NR_NB_SC_PER_RB) {
// Pseudo-random sequence c(i) defined by TS 38.211 - Section 5.2.1
uint32_t cinit = n_ID_SRS;
uint8_t c_last_index = (slot_number * N_SYMB_SLOT + l0 + l_line);
uint32_t *c_sequence = calloc(c_last_index+1, sizeof(uint32_t));
pseudo_random_sequence(c_last_index+1, c_sequence, cinit);
// TS 38.211 - 6.4.1.4.2 Sequence generation
v = c_sequence[c_last_index];
free(c_sequence);
}
return v;
}
uint16_t compute_F_b(frame_t frame_number,
slot_t slot_number,
uint16_t slots_per_frame,
uint8_t N_symb_SRS,
uint8_t B_SRS,
uint8_t C_SRS,
uint8_t b_hop,
uint8_t R,
uint16_t T_offset,
uint16_t T_SRS,
resourceType_t resource_type,
uint8_t l_line,
uint8_t b) {
// Compute the number of SRS transmissions
uint16_t n_SRS = 0;
if (resource_type == aperiodic) {
n_SRS = l_line / R;
} else {
n_SRS = ((slots_per_frame*frame_number + slot_number - T_offset)/T_SRS)*(N_symb_SRS/R)+(l_line / R);
}
uint16_t product_N_b = 1;
for (unsigned int b_prime = b_hop; b_prime < B_SRS; b_prime++) {
if (b_prime != b_hop) {
product_N_b *= get_N_b_srs(C_SRS, b_prime);
}
}
uint16_t F_b = 0;
uint8_t N_b = get_N_b_srs(C_SRS, b);
if (N_b & 1) { // Nb odd
F_b = (N_b/2)*(n_SRS/product_N_b);
} else { // Nb even
uint16_t product_N_b_B_SRS = product_N_b;
product_N_b_B_SRS *= get_N_b_srs(C_SRS, B_SRS); /* product for b_hop to b */
F_b = (N_b/2)*((n_SRS%product_N_b_B_SRS)/product_N_b) + ((n_SRS%product_N_b_B_SRS)/2*product_N_b);
}
return F_b;
}
uint16_t compute_n_b(frame_t frame_number,
slot_t slot_number,
uint16_t slots_per_frame,
uint8_t N_symb_SRS,
uint8_t B_SRS,
uint8_t C_SRS,
uint8_t b_hop,
uint8_t n_RRC,
uint8_t R,
uint16_t T_offset,
uint16_t T_SRS,
resourceType_t resource_type,
uint8_t l_line,
uint8_t b) {
uint8_t N_b = get_N_b_srs(C_SRS, b);
uint16_t m_SRS_b = get_m_srs(C_SRS, B_SRS);
uint16_t n_b = 0;
if (b_hop >= B_SRS) {
n_b = (4 * n_RRC/m_SRS_b)%N_b;
} else {
if (b <= b_hop) {
n_b = (4 * n_RRC/m_SRS_b)%N_b;
} else {
// Compute the hopping offset Fb
uint16_t F_b = compute_F_b(frame_number, slot_number, slots_per_frame, N_symb_SRS, B_SRS, C_SRS, b_hop, R,
T_offset, T_SRS, resource_type, l_line, b);
n_b = (F_b + (4 * n_RRC/m_SRS_b))%N_b;
}
}
return n_b;
}
/*************************************************************************
*
* NAME : generate_srs_nr
*
* PARAMETERS : pointer to srs config pdu
* pointer to transmit buffer
* amplitude scaling for this physical signal
* slot number of transmission
* RETURN : 0 if srs sequence has been successfully generated
* -1 if sequence can not be properly generated
*
* DESCRIPTION : generate/map srs symbol into transmit buffer
* See TS 38.211 - Section 6.4.1.4 Sounding reference signal
*
***************************************************************************/
int generate_srs_nr(nfapi_nr_srs_pdu_t *srs_config_pdu,
NR_DL_FRAME_PARMS *frame_parms,
c16_t **txdataF,
uint16_t symbol_offset,
nr_srs_info_t *nr_srs_info,
int16_t amp,
frame_t frame_number,
slot_t slot_number)
{
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"Calling %s function\n", __FUNCTION__);
#endif
// SRS config parameters
uint8_t B_SRS = srs_config_pdu->bandwidth_index;
uint8_t C_SRS = srs_config_pdu->config_index;
uint8_t b_hop = srs_config_pdu->frequency_hopping;
uint8_t K_TC = 2<<srs_config_pdu->comb_size;
uint8_t K_TC_overbar = srs_config_pdu->comb_offset;
uint8_t n_SRS_cs = srs_config_pdu->cyclic_shift;
uint8_t n_ID_SRS = srs_config_pdu->sequence_id;
uint8_t n_shift = srs_config_pdu->frequency_position; // It adjusts the SRS allocation to align with the common resource block grid in multiples of four
uint8_t n_RRC = srs_config_pdu->frequency_shift;
uint8_t groupOrSequenceHopping = srs_config_pdu->group_or_sequence_hopping;
uint8_t l_offset = srs_config_pdu->time_start_position;
uint16_t T_SRS = srs_config_pdu->t_srs;
uint16_t T_offset = srs_config_pdu->t_offset;
uint8_t R = 1<<srs_config_pdu->num_repetitions;
/* Number of antenna ports (M) can't be higher than number of physical antennas (N): M <= N */
uint8_t num_ant_ports = 1 << srs_config_pdu->num_ant_ports; // Number of antenna port for transmission
int N_ap = num_ant_ports > frame_parms->nb_antennas_tx ? frame_parms->nb_antennas_tx : num_ant_ports;
uint8_t N_symb_SRS = 1<<srs_config_pdu->num_symbols; // Number of consecutive OFDM symbols
uint8_t l0 = frame_parms->symbols_per_slot - 1 - l_offset; // Starting symbol position in the time domain
uint8_t n_SRS_cs_max = srs_max_number_cs[srs_config_pdu->comb_size];
uint16_t m_SRS_b = get_m_srs(C_SRS, B_SRS); // Number of resource blocks
uint16_t M_sc_b_SRS = m_SRS_b * NR_NB_SC_PER_RB/K_TC; // Length of the SRS sequence
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"Frame = %i, slot = %i\n", frame_number, slot_number);
LOG_I(NR_PHY,"B_SRS = %i\n", B_SRS);
LOG_I(NR_PHY,"C_SRS = %i\n", C_SRS);
LOG_I(NR_PHY,"b_hop = %i\n", b_hop);
LOG_I(NR_PHY,"K_TC = %i\n", K_TC);
LOG_I(NR_PHY,"K_TC_overbar = %i\n", K_TC_overbar);
LOG_I(NR_PHY,"n_SRS_cs = %i\n", n_SRS_cs);
LOG_I(NR_PHY,"n_ID_SRS = %i\n", n_ID_SRS);
LOG_I(NR_PHY,"n_shift = %i\n", n_shift);
LOG_I(NR_PHY,"n_RRC = %i\n", n_RRC);
LOG_I(NR_PHY,"groupOrSequenceHopping = %i\n", groupOrSequenceHopping);
LOG_I(NR_PHY,"l_offset = %i\n", l_offset);
LOG_I(NR_PHY,"T_SRS = %i\n", T_SRS);
LOG_I(NR_PHY,"T_offset = %i\n", T_offset);
LOG_I(NR_PHY,"R = %i\n", R);
LOG_I(NR_PHY,"N_ap = %i\n", N_ap);
LOG_I(NR_PHY,"N_symb_SRS = %i\n", N_symb_SRS);
LOG_I(NR_PHY,"l0 = %i\n", l0);
LOG_I(NR_PHY,"n_SRS_cs_max = %i\n", n_SRS_cs_max);
LOG_I(NR_PHY,"m_SRS_b = %i\n", m_SRS_b);
LOG_I(NR_PHY,"M_sc_b_SRS = %i\n", M_sc_b_SRS);
#endif
// Validation of SRS config parameters
if (R == 0) {
LOG_E(NR_PHY, "generate_srs: this parameter repetition factor %d is not consistent !\n", R);
return -1;
} else if (R > N_symb_SRS) {
LOG_E(NR_PHY, "generate_srs: R %d can not be greater than N_symb_SRS %d !\n", R, N_symb_SRS);
return -1;
}
if (n_SRS_cs >= n_SRS_cs_max) {
LOG_E(NR_PHY, "generate_srs: inconsistent parameter n_SRS_cs %d >= n_SRS_cs_max %d !\n", n_SRS_cs, n_SRS_cs_max);
return -1;
}
if (T_SRS == 0) {
LOG_E(NR_PHY, "generate_srs: inconsistent parameter T_SRS %d can not be equal to zero !\n", T_SRS);
return -1;
} else {
int index = 0;
while (srs_periodicity[index] != T_SRS) {
index++;
if (index == SRS_PERIODICITY) {
LOG_E(NR_PHY, "generate_srs: inconsistent parameter T_SRS %d not specified !\n", T_SRS);
return -1;
}
}
}
// Variable initialization
if(nr_srs_info) {
nr_srs_info->srs_generated_signal_bits = log2_approx(amp);
}
uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_config_pdu->bwp_start*NR_NB_SC_PER_RB;
double sqrt_N_ap = sqrt(N_ap);
uint16_t n_b[B_SRS + 1];
// Find index of table which is for this SRS length
uint16_t M_sc_b_SRS_index = 0;
while((ul_allocated_re[M_sc_b_SRS_index] != M_sc_b_SRS) && (M_sc_b_SRS_index < SRS_SB_CONF)){
M_sc_b_SRS_index++;
}
// SRS sequence generation and mapping, TS 38.211 - Section 6.4.1.4
for (int p_index = 0; p_index < N_ap; p_index++) {
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"============ port %d ============\n", p_index);
#endif
uint16_t n_SRS_cs_i = (n_SRS_cs + (n_SRS_cs_max * (SRS_antenna_port[p_index] - 1000)/N_ap))%n_SRS_cs_max;
double alpha_i = 2 * M_PI * ((double)n_SRS_cs_i / (double)n_SRS_cs_max);
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"n_SRS_cs_i = %i\n", n_SRS_cs_i);
LOG_I(NR_PHY,"alpha_i = %f\n", alpha_i);
#endif
for (int l_line = 0; l_line < N_symb_SRS; l_line++) {
#ifdef SRS_DEBUG
LOG_I(NR_PHY,":::::::: OFDM symbol %d ::::::::\n", l0+l_line);
#endif
// Set group and sequence numbers (u,v) per OFDM symbol
uint16_t u = 0;
uint16_t v = 0;
switch(groupOrSequenceHopping) {
case neitherHopping:
u = n_ID_SRS%U_GROUP_NUMBER;
v = 0;
break;
case groupHopping:
u = group_number_hopping(slot_number, n_ID_SRS, l0, l_line);
v = 0;
break;
case sequenceHopping:
u = n_ID_SRS%U_GROUP_NUMBER;
v = sequence_number_hopping(slot_number, n_ID_SRS, M_sc_b_SRS, l0, l_line);
break;
default:
LOG_E(NR_PHY, "generate_srs: unknown hopping setting %d !\n", groupOrSequenceHopping);
return -1;
}
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"u = %i\n", u);
LOG_I(NR_PHY,"v = %i\n", v);
#endif
// Compute the frequency position index n_b
uint16_t sum_n_b = 0;
for (int b = 0; b <= B_SRS; b++) {
n_b[b] = compute_n_b(frame_number, slot_number, frame_parms->slots_per_frame, N_symb_SRS, B_SRS,
C_SRS, b_hop, n_RRC, R, T_offset, T_SRS, srs_config_pdu->resource_type, l_line, b);
sum_n_b += n_b[b];
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"n_b[%i] = %i\n", b, n_b[b]);
#endif
}
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"sum_n_b = %i\n", sum_n_b);
#endif
// Compute the frequency-domain starting position
uint8_t K_TC_p = 0;
if((n_SRS_cs >= n_SRS_cs_max/2)&&(n_SRS_cs < n_SRS_cs_max)&&(N_ap == 4) && ((SRS_antenna_port[p_index] == 1001) || (SRS_antenna_port[p_index] == 1003))) {
K_TC_p = (K_TC_overbar + K_TC/2)%K_TC;
} else {
K_TC_p = K_TC_overbar;
}
uint8_t k_l_offset = 0; // If the SRS is configured by the IE SRS-PosResource-r16, the quantity k_l_offset is
// given by TS 38.211 - Table 6.4.1.4.3-2, otherwise k_l_offset = 0.
uint8_t k_0_overbar_p = (n_shift*NR_NB_SC_PER_RB + (K_TC_p+k_l_offset))%K_TC;
uint8_t k_0_p = k_0_overbar_p + K_TC*M_sc_b_SRS*sum_n_b;
nr_srs_info->k_0_p[p_index][l_line] = k_0_p;
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"K_TC_p = %i\n", K_TC_p);
LOG_I(NR_PHY,"k_0_overbar_p = %i\n", k_0_overbar_p);
LOG_I(NR_PHY,"k_0_p = %i\n", k_0_p);
#endif
uint16_t subcarrier = subcarrier_offset + k_0_p;
if (subcarrier>frame_parms->ofdm_symbol_size) {
subcarrier -= frame_parms->ofdm_symbol_size;
}
uint16_t l_line_offset = l_line*frame_parms->ofdm_symbol_size;
// For each port, and for each OFDM symbol, here it is computed and mapped an SRS sequence with M_sc_b_SRS symbols
for (int k = 0; k < M_sc_b_SRS; k++) {
cd_t shift = {cos(alpha_i * k), sin(alpha_i * k)};
const c16_t tmp = rv_ul_ref_sig[u][v][M_sc_b_SRS_index][k];
cd_t r_overbar = {tmp.r, tmp.i};
// cos(x+y) = cos(x)cos(y) - sin(x)sin(y)
cd_t r = cdMul(shift, r_overbar);
c16_t r_amp = {(((int32_t)round((double)amp * r.r / sqrt_N_ap)) >> 15),
(((int32_t)round((double)amp * r.i / sqrt_N_ap)) >> 15)};
#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, "(%d) \t%i\t%i\n", subcarrier_log, r_amp.r, r_amp.i);
#endif
txdataF[p_index][symbol_offset + l_line_offset + subcarrier] = r_amp;
// Subcarrier increment
subcarrier += K_TC;
if (subcarrier >= frame_parms->ofdm_symbol_size) {
subcarrier=subcarrier-frame_parms->ofdm_symbol_size;
}
} // for (int k = 0; k < M_sc_b_SRS; k++)
} // for (int l_line = 0; l_line < N_symb_SRS; l_line++)
} // for (int p_index = 0; p_index < N_ap; p_index++)
return 0;
}
/*******************************************************************
*
* NAME : ue_srs_procedures_nr
*
* PARAMETERS : pointer to ue context
* pointer to rxtx context*
*
* RETURN : 0 if it is a valid slot for transmitting srs
* -1 if srs should not be transmitted
*
* DESCRIPTION : ue srs procedure
* send srs according to current configuration
*
*********************************************************************/
int ue_srs_procedures_nr(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
c16_t **txdataF,
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT])
{
if(!ue->srs_vars[0]->active) {
return -1;
}
ue->srs_vars[0]->active = false;
nfapi_nr_srs_pdu_t *srs_config_pdu = (nfapi_nr_srs_pdu_t*)&ue->srs_vars[0]->srs_config_pdu;
int first_srs_symbol = ue->frame_parms.symbols_per_slot - 1 - srs_config_pdu->time_start_position;
// Num consecutive SRS symbols according to 38.211 6.4.1.4.1
int num_srs_symbols[] = {1, 2, 4, 8, 12};
int last_srs_symbol = first_srs_symbol + num_srs_symbols[srs_config_pdu->num_symbols] - 1;
for (int i = first_srs_symbol; i <= last_srs_symbol; i++) {
was_symbol_used[i] = true;
}
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"Frame = %i, slot = %i\n", proc->frame_tx, proc->nr_slot_tx);
LOG_I(NR_PHY,"srs_config_pdu->rnti = 0x%04x\n", srs_config_pdu->rnti);
LOG_I(NR_PHY,"srs_config_pdu->handle = %u\n", srs_config_pdu->handle);
LOG_I(NR_PHY,"srs_config_pdu->bwp_size = %u\n", srs_config_pdu->bwp_size);
LOG_I(NR_PHY,"srs_config_pdu->bwp_start = %u\n", srs_config_pdu->bwp_start);
LOG_I(NR_PHY,"srs_config_pdu->subcarrier_spacing = %u\n", srs_config_pdu->subcarrier_spacing);
LOG_I(NR_PHY,"srs_config_pdu->cyclic_prefix = %u (0: Normal; 1: Extended)\n", srs_config_pdu->cyclic_prefix);
LOG_I(NR_PHY,"srs_config_pdu->num_ant_ports = %u (0 = 1 port, 1 = 2 ports, 2 = 4 ports)\n", srs_config_pdu->num_ant_ports);
LOG_I(NR_PHY,"srs_config_pdu->num_symbols = %u (0 = 1 symbol, 1 = 2 symbols, 2 = 4 symbols)\n", srs_config_pdu->num_symbols);
LOG_I(NR_PHY,"srs_config_pdu->num_repetitions = %u (0 = 1, 1 = 2, 2 = 4)\n", srs_config_pdu->num_repetitions);
LOG_I(NR_PHY,"srs_config_pdu->time_start_position = %u\n", srs_config_pdu->time_start_position);
LOG_I(NR_PHY,"srs_config_pdu->config_index = %u\n", srs_config_pdu->config_index);
LOG_I(NR_PHY,"srs_config_pdu->sequence_id = %u\n", srs_config_pdu->sequence_id);
LOG_I(NR_PHY,"srs_config_pdu->bandwidth_index = %u\n", srs_config_pdu->bandwidth_index);
LOG_I(NR_PHY,"srs_config_pdu->comb_size = %u (0 = comb size 2, 1 = comb size 4, 2 = comb size 8)\n", srs_config_pdu->comb_size);
LOG_I(NR_PHY,"srs_config_pdu->comb_offset = %u\n", srs_config_pdu->comb_offset);
LOG_I(NR_PHY,"srs_config_pdu->cyclic_shift = %u\n", srs_config_pdu->cyclic_shift);
LOG_I(NR_PHY,"srs_config_pdu->frequency_position = %u\n", srs_config_pdu->frequency_position);
LOG_I(NR_PHY,"srs_config_pdu->frequency_shift = %u\n", srs_config_pdu->frequency_shift);
LOG_I(NR_PHY,"srs_config_pdu->frequency_hopping = %u\n", srs_config_pdu->frequency_hopping);
LOG_I(NR_PHY,"srs_config_pdu->group_or_sequence_hopping = %u (0 = No hopping, 1 = Group hopping groupOrSequenceHopping, 2 = Sequence hopping)\n", srs_config_pdu->group_or_sequence_hopping);
LOG_I(NR_PHY,"srs_config_pdu->resource_type = %u (0: aperiodic, 1: semi-persistent, 2: periodic)\n", srs_config_pdu->resource_type);
LOG_I(NR_PHY,"srs_config_pdu->t_srs = %u\n", srs_config_pdu->t_srs);
LOG_I(NR_PHY,"srs_config_pdu->t_offset = %u\n", srs_config_pdu->t_offset);
#endif
NR_DL_FRAME_PARMS *frame_parms = &(ue->frame_parms);
uint16_t symbol_offset = (frame_parms->symbols_per_slot - 1 - srs_config_pdu->time_start_position)*frame_parms->ofdm_symbol_size;
if (generate_srs_nr(srs_config_pdu, frame_parms, txdataF, symbol_offset, ue->nr_srs_info, AMP, proc->frame_tx, proc->nr_slot_tx)
== 0) {
return 0;
} else {
return -1;
}
}