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:
+14
-1
@@ -2037,6 +2037,19 @@ target_link_libraries(nr_ulsim PRIVATE
|
||||
)
|
||||
target_link_libraries(nr_ulsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
|
||||
add_executable(nr_srssim
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/srssim.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
${NFAPI_USER_DIR}/nfapi.c
|
||||
${NFAPI_USER_DIR}/gnb_ind_vars.c
|
||||
${PHY_INTERFACE_DIR}/queue_t.c
|
||||
)
|
||||
|
||||
target_link_libraries(nr_srssim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON nr_rrc L2_NR -lz -Wl,--end-group
|
||||
m pthread ITTI dl nr_ue_phy_meas physim_common
|
||||
)
|
||||
|
||||
# these simulators do not compile:
|
||||
# dlsim_tm7 pbchsim scansim mbmssim pdcchsim pucchsim prachsim syncsim
|
||||
foreach(myExe dlsim ulsim)
|
||||
@@ -2085,7 +2098,7 @@ if (${T_TRACER})
|
||||
nr-uesoftmodem dlsim dlsim_tm4 dlsim_tm7
|
||||
ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim
|
||||
syncsim nr_ulsim nr_dlsim nr_dlschsim nr_pbchsim nr_pucchsim
|
||||
nr_ulschsim ldpctest polartest smallblocktest
|
||||
nr_ulschsim ldpctest polartest smallblocktest nr_srssim
|
||||
#all "add_library" definitions
|
||||
ITTI lte_rrc nr_rrc s1ap x2ap m2ap m3ap f1ap
|
||||
params_libconfig
|
||||
|
||||
@@ -44,4 +44,4 @@ RUN cmake -GNinja -DENABLE_PHYSIM_TESTS=ON \
|
||||
-DCMAKE_C_FLAGS=-Werror -DCMAKE_CXX_FLAGS=-Werror \
|
||||
-DPHYSIM_CHECK_FILES="ThresholdsGracehopper.cmake" \
|
||||
.. && \
|
||||
ninja ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim
|
||||
ninja ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim nr_srssim
|
||||
|
||||
@@ -300,7 +300,7 @@ function main() {
|
||||
SIMUS_PHY=1
|
||||
CMAKE_CMD="$CMAKE_CMD -DENABLE_PHYSIM_TESTS=ON"
|
||||
# TODO: fix: dlsim_tm4 pucchsim prachsim pdcchsim pbchsim mbmssim
|
||||
TARGET_LIST="$TARGET_LIST dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim"
|
||||
TARGET_LIST="$TARGET_LIST dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim nr_srssim"
|
||||
echo_info "Will compile dlsim, ulsim, ..."
|
||||
shift;;
|
||||
-V | --vcd)
|
||||
|
||||
@@ -138,11 +138,11 @@ ID = GNB_PHY_UL_PAYLOAD_RX_BITS
|
||||
ID = GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE
|
||||
DESC = gNodeB channel estimation in the frequency domain
|
||||
GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB
|
||||
FORMAT = int,gNB_ID : int,rnti : int,frame : int,subframe : int,antenna : buffer,chest_t
|
||||
FORMAT = int,gNB_ID : int,rnti : int,frame : int,subframe : int,antenna : int,port : buffer,chest_f
|
||||
ID = GNB_PHY_UL_TIME_CHANNEL_ESTIMATE
|
||||
DESC = gNodeB channel estimation in the time domain
|
||||
GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB
|
||||
FORMAT = int,gNB_ID : int,rnti : int,frame : int,subframe : int,antenna : buffer,chest_t
|
||||
FORMAT = int,gNB_ID : int,rnti : int,frame : int,subframe : int,antenna : int,port : buffer,chest_t
|
||||
ID = GNB_PHY_UL_SNR_ESTIMATE
|
||||
DESC = gNodeB SNR estimation based on SRS
|
||||
GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB
|
||||
@@ -155,6 +155,10 @@ ID = GNB_PHY_DL_OUTPUT_SIGNAL
|
||||
DESC = gNodeB output data in the freq domain for slots
|
||||
GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB
|
||||
FORMAT = int,gNB_ID : int,frame : int,slot : int,antenna : buffer,txdata
|
||||
ID = GNB_PHY_UL_SRS_TOA_NS
|
||||
DESC = gNB ToA estimate from SRS (in ns)
|
||||
GROUP = ALL:PHY:GNB
|
||||
FORMAT = int,gNB_ID : int,rnti : int,frame : int,subframe : buffer,toa_ns
|
||||
|
||||
#MAC logs
|
||||
ID = ENB_MAC_UE_DL_SDU
|
||||
|
||||
@@ -360,6 +360,7 @@ float get_beta_dmrs(int num_cdm_groups_no_data, bool is_type2);
|
||||
|
||||
#define CEILIDIV(a,b) ((a+b-1)/b)
|
||||
#define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1))
|
||||
#define BOUNDED_EVAL(a, b, c) (min(c, max(a, b)))
|
||||
|
||||
static const char *const duplex_mode_txt[] = {"FDD", "TDD"};
|
||||
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ The main oai binaries, which are tested by the Continuous Integration process ar
|
||||
- The 5G gNodeB: `nr-softmodem`
|
||||
- The 5G CU-UP: `nr-cuup`
|
||||
- The LTE PHY simulators: `dlsim` and `ulsim`
|
||||
- The 5G PHY simulators: `nr_dlschsim`, `nr_dlsim`, `nr_pbchsim`, `nr_pucchsim`, `nr_ulschsim`, `nr_ulsim`, `polartest`, `smallblocktest`, `nr _ulsim`, `ldpctest`
|
||||
- The 5G PHY simulators: `nr_dlschsim`, `nr_dlsim`, `nr_pbchsim`, `nr_pucchsim`, `nr_ulschsim`, `nr_ulsim`, `polartest`, `smallblocktest`, `nr _ulsim`, `ldpctest`, `nr_srssim`
|
||||
|
||||
Running the [build_oai](../cmake_targets/build_oai) script also generates some utilities required to build and/or run the oai softmodem binaries:
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ be defined in order to tell cmake where the host tools have been built.
|
||||
cd ../build-cross
|
||||
cmake ../../.. -GNinja -DCMAKE_TOOLCHAIN_FILE=../../../cmake_targets/cross-arm.cmake -DNATIVE_DIR=../build
|
||||
|
||||
ninja dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim
|
||||
ninja dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_srssim
|
||||
ninja lte-softmodem nr-softmodem nr-cuup oairu lte-uesoftmodem nr-uesoftmodem
|
||||
ninja params_libconfig coding rfsimulator
|
||||
```
|
||||
|
||||
@@ -36,6 +36,7 @@ pipelines:
|
||||
| | `nr_pbchsim` | Broadcast channel simulation |
|
||||
| | `nr_prachsim` | PRACH simulation |
|
||||
| | `nr_psbchsim` | Sidelink simulation |
|
||||
| | `nr_srssim` | SRS simulation |
|
||||
| Coding | `ldpctest`, `polartest`, `smallblocktest` | LDPC, Polar, and other FEC tests |
|
||||
|
||||
## Source Locations
|
||||
|
||||
+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) {
|
||||
|
||||
@@ -199,8 +199,8 @@ void do_tdd_config_sim(PHY_VARS_gNB *gNB, int mu)
|
||||
switch (mu)
|
||||
{
|
||||
case 0:
|
||||
pc->num_dl_slots = 3;
|
||||
pc->num_ul_slots = 1;
|
||||
pc->num_dl_slots = 7;
|
||||
pc->num_ul_slots = 2;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
@@ -209,8 +209,8 @@ void do_tdd_config_sim(PHY_VARS_gNB *gNB, int mu)
|
||||
break;
|
||||
|
||||
case 3:
|
||||
pc->num_dl_slots = 27;
|
||||
pc->num_ul_slots = 12;
|
||||
pc->num_dl_slots = 7;
|
||||
pc->num_ul_slots = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -226,7 +226,7 @@ void do_tdd_config_sim(PHY_VARS_gNB *gNB, int mu)
|
||||
pc->tdd_slot_bitmap[i].num_dl_symbols = 6;
|
||||
pc->tdd_slot_bitmap[i].num_ul_symbols = 4;
|
||||
}
|
||||
for (int i = pc->num_ul_slots; i < fs.numb_slots_period; i++) {
|
||||
for (int i = fs.numb_slots_period - pc->num_ul_slots; i < fs.numb_slots_period; i++) {
|
||||
pc->tdd_slot_bitmap[i].slot_type = TDD_NR_UPLINK_SLOT;
|
||||
pc->tdd_slot_bitmap[i].num_dl_symbols = 0;
|
||||
pc->tdd_slot_bitmap[i].num_ul_symbols = 0;
|
||||
|
||||
@@ -717,9 +717,10 @@ static void fill_ul_rb_mask(PHY_VARS_gNB *gNB,
|
||||
if (!(srs && srs->active && srs->frame == frame_rx && srs->slot == slot_rx))
|
||||
continue;
|
||||
nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu;
|
||||
const uint8_t l0 = gNB->frame_parms.symbols_per_slot - 1 - srs_pdu->time_start_position;
|
||||
for (int symbol = 0; symbol < (1 << srs_pdu->num_symbols); symbol++) {
|
||||
for (int rb = srs_pdu->bwp_start; rb < (srs_pdu->bwp_start + srs_pdu->bwp_size); rb++) {
|
||||
rb_mask_ul[srs_pdu->time_start_position + symbol][rb >> 5] |= 1U << (rb & 31);
|
||||
rb_mask_ul[l0 + symbol][rb >> 5] |= 1U << (rb & 31);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -857,6 +858,139 @@ static bool check_and_configure_srs_info(nfapi_nr_srs_pdu_t *srs_config_pdu, nr_
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
|
||||
nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu;
|
||||
c16_t srs_received_signal[nb_antennas_rx][ofdm_symbol_size * N_symb_SRS];
|
||||
c16_t srs_received_noise[nb_antennas_rx][ofdm_symbol_size * N_symb_SRS];
|
||||
c16_t srs_estimated_channel_time_shifted[nb_antennas_rx][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size];
|
||||
|
||||
start_meas(&gNB->generate_srs_stats);
|
||||
|
||||
if (check_and_configure_srs_info(srs_pdu, nr_srs_info)) {
|
||||
generate_srs_nr(frame_parms,
|
||||
nr_srs_info->srs_generated_signal,
|
||||
0,
|
||||
srs_pdu->bwp_start,
|
||||
nr_srs_info,
|
||||
AMP,
|
||||
frame_rx,
|
||||
slot_rx,
|
||||
nb_antennas_rx);
|
||||
}
|
||||
|
||||
stop_meas(&gNB->generate_srs_stats);
|
||||
c16_t **rxdataF = gNB->common_vars.rxdataF[srs->beam_nb];
|
||||
start_meas(&gNB->get_srs_signal_stats);
|
||||
*srs_est = nr_get_srs_signal(gNB, rxdataF, frame_rx, slot_rx, srs_pdu, nr_srs_info, srs_received_signal, srs_received_noise);
|
||||
stop_meas(&gNB->get_srs_signal_stats);
|
||||
|
||||
uint32_t signal_power_avg = 0;
|
||||
uint32_t noise_power_avg = 0;
|
||||
int16_t noise_power_per_rb[srs_pdu->bwp_size];
|
||||
memset(noise_power_per_rb, 0, srs_pdu->bwp_size * sizeof(int16_t));
|
||||
|
||||
if (*srs_est >= 0) {
|
||||
start_meas(&gNB->srs_channel_estimation_stats);
|
||||
for (int ant_rx_ind = 0; ant_rx_ind < nb_antennas_rx; ant_rx_ind++) {
|
||||
uint32_t noise_power = 0;
|
||||
for (int p_ind = 0; p_ind < N_ap; p_ind++) {
|
||||
uint32_t signal_power = 0;
|
||||
nr_srs_channel_estimation(ant_rx_ind,
|
||||
p_ind,
|
||||
ofdm_symbol_size,
|
||||
frame_parms->first_carrier_offset,
|
||||
N_symb_SRS,
|
||||
srs_pdu,
|
||||
nr_srs_info,
|
||||
nr_srs_info->srs_generated_signal[p_ind],
|
||||
srs_received_signal[ant_rx_ind],
|
||||
srs_received_noise[ant_rx_ind],
|
||||
srs_estimated_channel_freq[ant_rx_ind][p_ind],
|
||||
srs_estimated_channel_time[ant_rx_ind][p_ind],
|
||||
srs_estimated_channel_time_shifted[ant_rx_ind][p_ind],
|
||||
&signal_power,
|
||||
&noise_power,
|
||||
noise_power_per_rb);
|
||||
|
||||
signal_power_avg += signal_power;
|
||||
|
||||
T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE,
|
||||
T_INT(gNB->Mod_id),
|
||||
T_INT(srs_pdu->rnti),
|
||||
T_INT(frame_rx),
|
||||
T_INT(slot_rx),
|
||||
T_INT(ant_rx_ind),
|
||||
T_INT(p_ind),
|
||||
T_BUFFER(srs_estimated_channel_freq[ant_rx_ind][p_ind], N_symb_SRS * ofdm_symbol_size * sizeof(c16_t)));
|
||||
|
||||
T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE,
|
||||
T_INT(gNB->Mod_id),
|
||||
T_INT(srs_pdu->rnti),
|
||||
T_INT(frame_rx),
|
||||
T_INT(slot_rx),
|
||||
T_INT(ant_rx_ind),
|
||||
T_INT(p_ind),
|
||||
T_BUFFER(srs_estimated_channel_time_shifted[ant_rx_ind][p_ind],
|
||||
NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size * sizeof(c16_t)));
|
||||
}
|
||||
noise_power_avg += noise_power;
|
||||
}
|
||||
signal_power_avg /= (nb_antennas_rx * N_ap);
|
||||
noise_power_avg /= nb_antennas_rx;
|
||||
signal_power_avg = max(signal_power_avg, 1);
|
||||
gNB->srs->snr = dB_fixed(signal_power_avg) - dB_fixed(max(noise_power_avg, 1));
|
||||
|
||||
const uint16_t m_SRS_b = get_m_srs(srs_pdu->config_index, srs_pdu->bandwidth_index);
|
||||
for (int rb = 0; rb < m_SRS_b; rb++) {
|
||||
snr_per_rb[rb] = dB_fixed(signal_power_avg) - dB_fixed(max(noise_power_per_rb[rb] / nb_antennas_rx, 1));
|
||||
}
|
||||
stop_meas(&gNB->srs_channel_estimation_stats);
|
||||
|
||||
start_meas(&gNB->srs_timing_advance_stats);
|
||||
for (int ant_rx_ind = 0; ant_rx_ind < nb_antennas_rx; ant_rx_ind++) {
|
||||
nr_est_srs_timing_advance_offset(ofdm_symbol_size,
|
||||
srs_estimated_channel_time[ant_rx_ind],
|
||||
ant_rx_ind,
|
||||
N_ap,
|
||||
frame_parms->samples_per_frame,
|
||||
timing_advance_offset,
|
||||
&timing_advance_offset_nsec[ant_rx_ind]);
|
||||
}
|
||||
stop_meas(&gNB->srs_timing_advance_stats);
|
||||
|
||||
T(T_GNB_PHY_UL_SNR_ESTIMATE,
|
||||
T_INT(0),
|
||||
T_INT(srs_pdu->rnti),
|
||||
T_INT(frame_rx),
|
||||
T_INT(0),
|
||||
T_INT(0),
|
||||
T_BUFFER(snr_per_rb, srs_pdu->bwp_size * sizeof(int16_t)));
|
||||
|
||||
T(T_GNB_PHY_UL_SRS_TOA_NS,
|
||||
T_INT(gNB->Mod_id),
|
||||
T_INT(srs_pdu->rnti),
|
||||
T_INT(frame_rx),
|
||||
T_INT(slot_rx),
|
||||
T_BUFFER(timing_advance_offset_nsec, nb_antennas_rx * sizeof(int16_t)));
|
||||
}
|
||||
}
|
||||
|
||||
int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, NR_UL_IND_t *UL_INFO)
|
||||
{
|
||||
/* those variables to log T_GNB_PHY_PUCCH_PUSCH_IQ only when we try to decode */
|
||||
@@ -865,9 +999,9 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
|
||||
int pusch_DTX = 0;
|
||||
|
||||
const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
|
||||
const int symb_sz = frame_parms->ofdm_symbol_size;
|
||||
const uint16_t ofdm_symbol_size = frame_parms->ofdm_symbol_size;
|
||||
const int nb_symb = frame_parms->symbols_per_slot;
|
||||
const int ant = gNB->frame_parms.nb_antennas_rx;
|
||||
const uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx;
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,1);
|
||||
LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d\n",frame_rx,slot_rx);
|
||||
{
|
||||
@@ -892,7 +1026,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
|
||||
gNB_I0_measurements(gNB, slot_rx, first_symb, num_symb, rb_mask_ul);
|
||||
}
|
||||
|
||||
const int soffset = (slot_rx & 3) * nb_symb * symb_sz;
|
||||
const int soffset = (slot_rx & 3) * nb_symb * ofdm_symbol_size;
|
||||
start_meas(&gNB->phy_proc_rx);
|
||||
|
||||
for (int i = 0; i < gNB->max_nb_pucch; i++) {
|
||||
@@ -911,7 +1045,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
|
||||
uci->pdu_type = NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE;
|
||||
uci->pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_0_1_t);
|
||||
nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu_format0 = &uci->pucch_pdu_format_0_1;
|
||||
int offset = pucch_pdu->start_symbol_index * symb_sz + (frame_parms->first_carrier_offset + pucch_pdu->prb_start * 12);
|
||||
int offset =
|
||||
pucch_pdu->start_symbol_index * ofdm_symbol_size + (frame_parms->first_carrier_offset + pucch_pdu->prb_start * 12);
|
||||
LOG_D(NR_PHY,
|
||||
"frame %d, slot %d: PUCCH signal energy %d\n",
|
||||
frame_rx,
|
||||
@@ -988,7 +1123,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
|
||||
NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ULSCH_id];
|
||||
pusch_vars->ulsch_power_tot = 0;
|
||||
pusch_vars->ulsch_noise_power_tot = 0;
|
||||
for (int aarx = 0; aarx < ant; aarx++) {
|
||||
for (int aarx = 0; aarx < nb_antennas_rx; aarx++) {
|
||||
pusch_vars->ulsch_power[aarx] /= num_dmrs;
|
||||
pusch_vars->ulsch_power_tot += pusch_vars->ulsch_power[aarx];
|
||||
pusch_vars->ulsch_noise_power[aarx] /= num_dmrs;
|
||||
@@ -1063,80 +1198,38 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
|
||||
|
||||
start_meas(&gNB->rx_srs_stats);
|
||||
|
||||
uint8_t N_symb_SRS = 1 << srs->srs_pdu.num_symbols;
|
||||
uint8_t N_ap = 1 << srs->srs_pdu.num_ant_ports;
|
||||
int16_t snr_per_rb[srs->srs_pdu.bwp_size];
|
||||
nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu;
|
||||
uint8_t N_symb_SRS = 1 << srs_pdu->num_symbols;
|
||||
c16_t srs_received_signal[ant][symb_sz * N_symb_SRS];
|
||||
c16_t srs_received_noise[ant][symb_sz * N_symb_SRS];
|
||||
c16_t srs_estimated_channel_freq[ant][1 << srs_pdu->num_ant_ports][symb_sz * N_symb_SRS] __attribute__((aligned(32)));
|
||||
c16_t srs_estimated_channel_time[ant][1 << srs_pdu->num_ant_ports][symb_sz] __attribute__((aligned(32)));
|
||||
c16_t srs_estimated_channel_time_shifted[ant][1 << srs_pdu->num_ant_ports][symb_sz];
|
||||
int16_t snr_per_rb[srs_pdu->bwp_size];
|
||||
uint16_t timing_advance_offset;
|
||||
int16_t timing_advance_offset_nsec[nb_antennas_rx];
|
||||
int srs_est;
|
||||
|
||||
start_meas(&gNB->generate_srs_stats);
|
||||
c16_t srs_estimated_channel_freq[nb_antennas_rx][N_ap][ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32)));
|
||||
c16_t srs_estimated_channel_time[nb_antennas_rx][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size]
|
||||
__attribute__((aligned(32)));
|
||||
|
||||
if (check_and_configure_srs_info(srs_pdu, gNB->nr_srs_info[i])) {
|
||||
generate_srs_nr(frame_parms,
|
||||
gNB->nr_srs_info[i]->srs_generated_signal,
|
||||
0,
|
||||
srs_pdu->bwp_start,
|
||||
gNB->nr_srs_info[i],
|
||||
AMP,
|
||||
frame_rx,
|
||||
slot_rx);
|
||||
}
|
||||
stop_meas(&gNB->generate_srs_stats);
|
||||
c16_t **rxdataF = gNB->common_vars.rxdataF[srs->beam_nb];
|
||||
start_meas(&gNB->get_srs_signal_stats);
|
||||
int srs_est =
|
||||
nr_get_srs_signal(gNB, rxdataF, frame_rx, slot_rx, srs_pdu, gNB->nr_srs_info[i], srs_received_signal, srs_received_noise);
|
||||
stop_meas(&gNB->get_srs_signal_stats);
|
||||
|
||||
if (srs_est >= 0) {
|
||||
start_meas(&gNB->srs_channel_estimation_stats);
|
||||
nr_srs_channel_estimation(gNB,
|
||||
frame_rx,
|
||||
slot_rx,
|
||||
srs_pdu,
|
||||
gNB->nr_srs_info[i],
|
||||
(const c16_t **)gNB->nr_srs_info[i]->srs_generated_signal,
|
||||
srs_received_signal,
|
||||
srs_received_noise,
|
||||
srs_estimated_channel_freq,
|
||||
srs_estimated_channel_time,
|
||||
srs_estimated_channel_time_shifted,
|
||||
snr_per_rb,
|
||||
&gNB->srs->snr);
|
||||
stop_meas(&gNB->srs_channel_estimation_stats);
|
||||
}
|
||||
nr_srs_rx_procedures(gNB,
|
||||
frame_rx,
|
||||
slot_rx,
|
||||
nb_antennas_rx,
|
||||
N_ap,
|
||||
N_symb_SRS,
|
||||
ofdm_symbol_size,
|
||||
srs,
|
||||
gNB->nr_srs_info[i],
|
||||
&srs_est,
|
||||
srs_estimated_channel_freq,
|
||||
srs_estimated_channel_time,
|
||||
snr_per_rb,
|
||||
&timing_advance_offset,
|
||||
timing_advance_offset_nsec);
|
||||
|
||||
if ((gNB->srs->snr * 10) < gNB->srs_thres) {
|
||||
srs_est = -1;
|
||||
}
|
||||
|
||||
T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE,
|
||||
T_INT(0),
|
||||
T_INT(srs_pdu->rnti),
|
||||
T_INT(frame_rx),
|
||||
T_INT(0),
|
||||
T_INT(0),
|
||||
T_BUFFER(srs_estimated_channel_freq[0][0], symb_sz * sizeof(int32_t)));
|
||||
|
||||
T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE,
|
||||
T_INT(0),
|
||||
T_INT(srs_pdu->rnti),
|
||||
T_INT(frame_rx),
|
||||
T_INT(0),
|
||||
T_INT(0),
|
||||
T_BUFFER(srs_estimated_channel_time_shifted[0][0], symb_sz * sizeof(int32_t)));
|
||||
|
||||
T(T_GNB_PHY_UL_SNR_ESTIMATE,
|
||||
T_INT(0),
|
||||
T_INT(srs_pdu->rnti),
|
||||
T_INT(frame_rx),
|
||||
T_INT(0),
|
||||
T_INT(0),
|
||||
T_BUFFER(snr_per_rb, srs_pdu->bwp_size * sizeof(int16_t)));
|
||||
|
||||
UL_INFO->srs_ind.sfn = frame_rx;
|
||||
UL_INFO->srs_ind.slot = slot_rx;
|
||||
|
||||
@@ -1145,13 +1238,9 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
|
||||
nfapi_nr_srs_indication_pdu_t *srs_indication = UL_INFO->srs_pdu_list + UL_INFO->srs_ind.number_of_pdus++;
|
||||
srs_indication->handle = srs_pdu->handle;
|
||||
srs_indication->rnti = srs_pdu->rnti;
|
||||
start_meas(&gNB->srs_timing_advance_stats);
|
||||
srs_indication->timing_advance_offset =
|
||||
srs_est >= 0 ? nr_est_timing_advance_srs(frame_parms, srs_estimated_channel_time[0]) : 0xFFFF;
|
||||
stop_meas(&gNB->srs_timing_advance_stats);
|
||||
srs_indication->timing_advance_offset_nsec =
|
||||
srs_est >= 0 ? (int16_t)((((int32_t)srs_indication->timing_advance_offset - 31) * ((int32_t)TC_NSEC_x32768)) >> 15)
|
||||
: 0xFFFF;
|
||||
srs_indication->timing_advance_offset = srs_est >= 0 ? timing_advance_offset : 0xFFFF;
|
||||
// TODO: currently we fill timing_advance_offset_nsec for antenna 0. Need to extend it for other antennas
|
||||
srs_indication->timing_advance_offset_nsec = srs_est >= 0 ? timing_advance_offset_nsec[0] : 0x8000;
|
||||
switch (srs_pdu->srs_parameters_v4.usage) {
|
||||
case 0:
|
||||
LOG_W(NR_PHY, "SRS report was not requested by MAC\n");
|
||||
@@ -1193,10 +1282,10 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
|
||||
start_meas(&gNB->srs_beam_report_stats);
|
||||
nfapi_nr_srs_beamforming_report_t nr_srs_bf_report;
|
||||
nr_srs_bf_report.prg_size = srs_pdu->beamforming.prg_size;
|
||||
nr_srs_bf_report.num_symbols = 1 << srs_pdu->num_symbols;
|
||||
nr_srs_bf_report.num_symbols = N_symb_SRS;
|
||||
nr_srs_bf_report.wide_band_snr =
|
||||
srs_est >= 0 ? (gNB->srs->snr + 64) << 1 : 0xFF; // 0xFF will be set if this field is invalid
|
||||
nr_srs_bf_report.num_reported_symbols = 1 << srs_pdu->num_symbols;
|
||||
nr_srs_bf_report.num_reported_symbols = N_symb_SRS;
|
||||
AssertFatal(nr_srs_bf_report.num_reported_symbols == 1,
|
||||
"nr_srs_bf_report.num_reported_symbols %i not handled yet!\n",
|
||||
nr_srs_bf_report.num_reported_symbols);
|
||||
@@ -1234,7 +1323,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
|
||||
srs_pdu,
|
||||
gNB->nr_srs_info[i],
|
||||
srs_pdu->srs_parameters_v4.iq_representation,
|
||||
ant,
|
||||
nb_antennas_rx,
|
||||
srs_pdu->srs_parameters_v4.num_total_ue_antennas,
|
||||
srs_pdu->srs_parameters_v4.prg_size,
|
||||
srs_pdu->srs_parameters_v4.srs_bandwidth_size / srs_pdu->srs_parameters_v4.prg_size,
|
||||
@@ -1306,7 +1395,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
|
||||
T(T_GNB_PHY_PUCCH_PUSCH_IQ,
|
||||
T_INT(frame_rx),
|
||||
T_INT(slot_rx),
|
||||
T_BUFFER(&gNB->common_vars.rxdataF[0][0][0], nb_symb * symb_sz * 4));
|
||||
T_BUFFER(&gNB->common_vars.rxdataF[0][0][0], nb_symb * ofdm_symbol_size * 4));
|
||||
}
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,0);
|
||||
|
||||
@@ -304,7 +304,7 @@ static void configure_srs_info(fapi_nr_ul_config_srs_pdu *srs_config_pdu, nr_srs
|
||||
* send srs according to current configuration
|
||||
*
|
||||
*********************************************************************/
|
||||
static bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue,
|
||||
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,
|
||||
@@ -314,12 +314,13 @@ static bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue,
|
||||
return false;
|
||||
}
|
||||
|
||||
NR_DL_FRAME_PARMS *frame_parms = &(ue->frame_parms);
|
||||
fapi_nr_ul_config_srs_pdu *srs_config_pdu = &phy_data->srs_vars.srs_config_pdu;
|
||||
int first_srs_symbol = ue->frame_parms.symbols_per_slot - 1 - srs_config_pdu->time_start_position;
|
||||
const uint8_t l0 = 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++) {
|
||||
int last_srs_symbol = l0 + num_srs_symbols[srs_config_pdu->num_symbols] - 1;
|
||||
for (int i = l0; i <= last_srs_symbol; i++) {
|
||||
was_symbol_used[i] = true;
|
||||
}
|
||||
|
||||
@@ -351,8 +352,7 @@ static bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue,
|
||||
#endif
|
||||
|
||||
configure_srs_info(srs_config_pdu, ue->nr_srs_info);
|
||||
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;
|
||||
uint16_t symbol_offset = l0 * frame_parms->ofdm_symbol_size;
|
||||
bool generated = generate_srs_nr(frame_parms,
|
||||
txdataF,
|
||||
symbol_offset,
|
||||
@@ -360,7 +360,8 @@ static bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue,
|
||||
ue->nr_srs_info,
|
||||
AMP,
|
||||
proc->frame_tx,
|
||||
proc->nr_slot_tx);
|
||||
proc->nr_slot_tx,
|
||||
frame_parms->nb_antennas_tx);
|
||||
return generated;
|
||||
}
|
||||
|
||||
@@ -400,15 +401,14 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n
|
||||
const NR_UE_PRACH *prach_var = ue->prach_vars[proc->gNB_id];
|
||||
if (!prach_var->active) {
|
||||
start_meas_nr_ue_phy(ue, OFDM_MOD_STATS);
|
||||
nr_ue_pusch_common_procedures(ue,
|
||||
proc->nr_slot_tx,
|
||||
&ue->frame_parms,
|
||||
ue->frame_parms.nb_antennas_tx,
|
||||
(c16_t **)txdataF,
|
||||
txp,
|
||||
link_type_ul,
|
||||
was_symbol_used,
|
||||
ue->no_phase_pre_comp);
|
||||
nr_tx_rotation_and_ofdm_mod(proc->nr_slot_tx,
|
||||
&ue->frame_parms,
|
||||
ue->frame_parms.nb_antennas_tx,
|
||||
(c16_t **)txdataF,
|
||||
txp,
|
||||
link_type_ul,
|
||||
was_symbol_used,
|
||||
ue->no_phase_pre_comp);
|
||||
stop_meas_nr_ue_phy(ue, OFDM_MOD_STATS);
|
||||
}
|
||||
|
||||
|
||||
@@ -315,15 +315,14 @@ void phy_procedures_nrUE_SL_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc
|
||||
was_symbol_used[i] = true;
|
||||
if (tx_action) {
|
||||
LOG_D(NR_PHY, "Sending Uplink data \n");
|
||||
nr_ue_pusch_common_procedures(ue,
|
||||
proc->nr_slot_tx,
|
||||
fp,
|
||||
fp->nb_antennas_tx,
|
||||
txdataF,
|
||||
txp,
|
||||
link_type_sl,
|
||||
was_symbol_used,
|
||||
ue->no_phase_pre_comp);
|
||||
nr_tx_rotation_and_ofdm_mod(proc->nr_slot_tx,
|
||||
fp,
|
||||
fp->nb_antennas_tx,
|
||||
txdataF,
|
||||
txp,
|
||||
link_type_sl,
|
||||
was_symbol_used,
|
||||
ue->no_phase_pre_comp);
|
||||
}
|
||||
|
||||
LOG_D(NR_PHY, "****** end Sidelink TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx);
|
||||
|
||||
@@ -324,7 +324,7 @@ int main(int argc, char **argv)
|
||||
setbuf(stdout, NULL);
|
||||
int c;
|
||||
int i,aa;//,l;
|
||||
double sigma2, sigma2_dB=10, SNR, snr0=-2.0, snr1=2.0;
|
||||
double SNR, snr0 = -2.0, snr1 = 2.0;
|
||||
uint8_t snr1set=0;
|
||||
double effRate;
|
||||
//float psnr;
|
||||
@@ -1172,15 +1172,12 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
int txlev[n_tx];
|
||||
int txlev_sum = 0;
|
||||
// Compute transmitter energy level
|
||||
int l_ofdm = 6;
|
||||
for (aa=0; aa<n_tx; aa++) {
|
||||
txlev[aa] = signal_energy((int32_t *)&txdata[aa][slot_offset +l_ofdm*frame_parms->ofdm_symbol_size + (l_ofdm-1)*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0],
|
||||
frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples);
|
||||
txlev_sum += txlev[aa];
|
||||
if (n_trials==1) printf("txlev[%d] = %d (%f dB) txlev_sum %d\n",aa,txlev[aa],10*log10((double)txlev[aa]),txlev_sum);
|
||||
}
|
||||
int symbol_offset = slot_offset + l_ofdm * frame_parms->ofdm_symbol_size + (l_ofdm - 1) * frame_parms->nb_prefix_samples
|
||||
+ frame_parms->nb_prefix_samples0;
|
||||
int symbol_length = frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples;
|
||||
double txlev_sum = compute_tx_energy_level(txdata, n_tx, symbol_offset, symbol_length, n_trials);
|
||||
|
||||
for (i = 0; i < slot_length; i++) {
|
||||
for (aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
|
||||
@@ -1189,11 +1186,11 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
double ts = 1.0/(frame_parms->subcarrier_spacing * frame_parms->ofdm_symbol_size);
|
||||
//Compute AWGN variance
|
||||
sigma2_dB = 10 * log10((double)txlev_sum * ((double)UE->frame_parms.ofdm_symbol_size/(12*pdsch_pdu_rel15->rbSize))) - SNR;
|
||||
sigma2 = pow(10, sigma2_dB/10);
|
||||
if (n_trials==1) printf("sigma2 %f (%f dB), txlev_sum %f (factor %f)\n",sigma2,sigma2_dB,10*log10((double)txlev_sum),(double)(double)UE->frame_parms.ofdm_symbol_size/(12*pdsch_pdu_rel15->rbSize));
|
||||
double ts = 1.0/(frame_parms->subcarrier_spacing * frame_parms->ofdm_symbol_size);
|
||||
|
||||
// Estimate noise power from the transmitter level and SNR
|
||||
double sigma2 =
|
||||
compute_noise_variance(txlev_sum, UE->frame_parms.ofdm_symbol_size, pdsch_pdu_rel15->rbSize, 1, SNR, n_trials);
|
||||
|
||||
for (aa = 0; aa < n_rx; aa++) {
|
||||
bzero(r_re[aa], slot_length * sizeof(double));
|
||||
|
||||
@@ -131,7 +131,7 @@ int main(int argc, char **argv){
|
||||
sigaction(SIGINT, &sigint_action, &oldaction);
|
||||
|
||||
get_softmodem_params()->sl_mode = 0;
|
||||
double sigma2, sigma2_dB = 0, SNR, snr0 = -2.0, snr1 = 0.0, ue_speed0 = 0.0, ue_speed1 = 0.0;
|
||||
double SNR, snr0 = -2.0, snr1 = 0.0, ue_speed0 = 0.0, ue_speed1 = 0.0;
|
||||
double **s_re, **s_im, **r_re, **r_im, iqim = 0.0, delay_avg = 0, ue_speed = 0, fs=-1, bw;
|
||||
int i, l, aa, aarx, trial, n_frames = 1, rx_prach_start; //, ntrials=1;
|
||||
c16_t **txdata;
|
||||
@@ -728,14 +728,7 @@ int main(int argc, char **argv){
|
||||
|
||||
for (trial = 0; trial < n_frames && !stop; trial++) {
|
||||
if (input_fd == NULL) {
|
||||
sigma2_dB = 10*log10((double)tx_lev) - SNR - 10*log10(N_RB_UL*12/N_ZC);
|
||||
|
||||
if (n_frames==1)
|
||||
printf("sigma2_dB %f (SNR %f dB) tx_lev_dB %f\n",sigma2_dB,SNR,10*log10((double)tx_lev));
|
||||
|
||||
//AWGN
|
||||
sigma2 = pow(10,sigma2_dB/10);
|
||||
// printf("Sigma2 %f (sigma2_dB %f)\n",sigma2,sigma2_dB);
|
||||
double sigma2 = compute_noise_variance(tx_lev, N_ZC, N_RB_UL, 1, SNR, n_frames);
|
||||
|
||||
if (awgn_flag == 0) {
|
||||
multipath_tv_channel(UE2gNB, s_re, s_im, r_re, r_im, frame_parms->samples_per_frame, 0);
|
||||
|
||||
@@ -96,7 +96,7 @@ int main(int argc, char **argv)
|
||||
sigaction(SIGINT, &sigint_action, &oldaction);
|
||||
|
||||
int i;//,l;
|
||||
double sigma2, sigma2_dB=10,SNR,snr0=-2.0,snr1=2.0;
|
||||
double SNR, snr0 = -2.0, snr1 = 2.0;
|
||||
double cfo=0;
|
||||
uint8_t snr1set=0;
|
||||
double **s_re,**s_im,**r_re,**r_im;
|
||||
@@ -566,15 +566,16 @@ int main(int argc, char **argv)
|
||||
// SNR Computation
|
||||
// standard says: SNR = S / N, where S is the total signal energy, N is the noise energy in the transmission bandwidth (i.e. N_RB_DL resource blocks)
|
||||
// txlev = S.
|
||||
int txlev = signal_energy((int32_t *)&txdataF[0][startingSymbolIndex*frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size);
|
||||
|
||||
// Compute transmitter energy level
|
||||
int symbol_offset = startingSymbolIndex * frame_parms->ofdm_symbol_size;
|
||||
int symbol_length = frame_parms->ofdm_symbol_size;
|
||||
double txlev = compute_tx_energy_level(txdataF, 1, symbol_offset, symbol_length, n_trials);
|
||||
|
||||
// sigma2 is variance per dimension, so N/(N_RB*12)
|
||||
// so, sigma2 = N/(N_RB_DL*12) => (S/SNR)/(N_RB*12)
|
||||
int N_RB = (format == 0 || format == 1) ? 1 : nrofPRB;
|
||||
sigma2_dB = 10*log10(txlev*(N_RB_DL/N_RB))-SNR;
|
||||
sigma2 = pow(10.0,sigma2_dB/10.0);
|
||||
|
||||
if (n_trials==1) printf("txlev %d (%f dB), offset %d, sigma2 %f ( %f dB)\n",txlev,10*log10(txlev),startingSymbolIndex*frame_parms->ofdm_symbol_size,sigma2,sigma2_dB);
|
||||
double sigma2 = compute_noise_variance(txlev, N_RB_DL * 12, N_RB, 1, SNR, n_trials);
|
||||
|
||||
for (int symb=0; symb<gNB->frame_parms.symbols_per_slot;symb++) {
|
||||
if (symb<startingSymbolIndex || symb >= startingSymbolIndex+nrofSymbols) {
|
||||
@@ -648,7 +649,16 @@ int main(int argc, char **argv)
|
||||
gNB_I0_measurements(gNB, nr_slot_tx, 0, gNB->frame_parms.symbols_per_slot, rb_mask_ul);
|
||||
start_meas(&gNB->phy_proc_rx);
|
||||
|
||||
if (n_trials==1) printf("noise rxlev %d (%d dB), rxlev pucch %d dB sigma2 %f dB, SNR %f, TX %f, I0 (pucch) %d, I0 (avg) %d\n",rxlev,dB_fixed(rxlev),dB_fixed(rxlev_pucch),sigma2_dB,SNR,10*log10((double)txlev*UE->frame_parms.ofdm_symbol_size/12),gNB->measurements.n0_subband_power_tot_dB[startingPRB],gNB->measurements.n0_subband_power_avg_dB);
|
||||
if (n_trials == 1)
|
||||
printf("noise rxlev %d (%d dB), rxlev pucch %d dB sigma2 %f dB, SNR %f, TX %f, I0 (pucch) %d, I0 (avg) %d\n",
|
||||
rxlev,
|
||||
dB_fixed(rxlev),
|
||||
dB_fixed(rxlev_pucch),
|
||||
10 * log10(sigma2),
|
||||
SNR,
|
||||
10 * log10((double)txlev * UE->frame_parms.ofdm_symbol_size / 12),
|
||||
gNB->measurements.n0_subband_power_tot_dB[startingPRB],
|
||||
gNB->measurements.n0_subband_power_avg_dB);
|
||||
if(format==0){
|
||||
nfapi_nr_uci_pucch_pdu_format_0_1_t uci_pdu;
|
||||
nfapi_nr_pucch_pdu_t pucch_pdu;
|
||||
|
||||
@@ -0,0 +1,690 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
#include "common/utils/var_array.h"
|
||||
#define inMicroS(a) (((double)(a)) / (get_cpu_freq_GHz() * 1000.0))
|
||||
#include "SIMULATION/LTE_PHY/common_sim.h"
|
||||
#include "common/utils/assertions.h"
|
||||
#include "PHY/INIT/nr_phy_init.h"
|
||||
#include "PHY/MODULATION/nr_modulation.h"
|
||||
#include "PHY/MODULATION/modulation_common.h"
|
||||
#include "PHY/NR_REFSIG/ul_ref_seq_nr.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
|
||||
#include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h"
|
||||
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
|
||||
#include "PHY/NR_ESTIMATION/nr_ul_estimation.h"
|
||||
#include "PHY/phy_vars_nr_ue.h"
|
||||
#include "e1ap_messages_types.h"
|
||||
#include "executables/nr-uesoftmodem.h"
|
||||
#include "SIMULATION/NR_PHY/nr_unitary_defs.h"
|
||||
#include "SIMULATION/TOOLS/sim.h"
|
||||
#include "common/ran_context.h"
|
||||
#include "time_meas.h"
|
||||
#include "SCHED_NR/phy_frame_config_nr.h"
|
||||
|
||||
PHY_VARS_gNB *gNB;
|
||||
PHY_VARS_NR_UE *UE;
|
||||
RAN_CONTEXT_t RC;
|
||||
char *uecap_file = NULL;
|
||||
int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
|
||||
|
||||
double cpuf;
|
||||
uint64_t downlink_frequency[MAX_NUM_CCs][4];
|
||||
uint64_t uplink_frequency[MAX_NUM_CCs][4];
|
||||
THREAD_STRUCT thread_struct;
|
||||
|
||||
// needed for some functions
|
||||
uint16_t n_rnti = 0x1234;
|
||||
openair0_config_t openair0_cfg[MAX_CARDS];
|
||||
nrUE_params_t nrUE_params;
|
||||
|
||||
nrUE_params_t *get_nrUE_params(void)
|
||||
{
|
||||
return &nrUE_params;
|
||||
}
|
||||
|
||||
channel_desc_t *UE2gNB[MAX_MOBILES_PER_GNB][NUMBER_OF_gNB_MAX];
|
||||
configmodule_interface_t *uniqCfg = NULL;
|
||||
|
||||
void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
stop = false;
|
||||
__attribute__((unused)) struct sigaction oldaction;
|
||||
sigaction(SIGINT, &sigint_action, &oldaction);
|
||||
|
||||
double SNR, snr0 = 0, snr1 = 20.0;
|
||||
double snr_step = 1;
|
||||
uint8_t snr1set = 0;
|
||||
double **s_re, **s_im, **r_re, **r_im;
|
||||
int trial, n_trials = 1, delay = 0;
|
||||
double maxDoppler = 0.0;
|
||||
uint8_t n_tx = 1, n_rx = 1;
|
||||
channel_desc_t *UE2gNB;
|
||||
uint8_t extended_prefix_flag = 0;
|
||||
SCM_t channel_model = AWGN;
|
||||
corr_level_t corr_level = CORR_LEVEL_LOW;
|
||||
uint16_t N_RB_DL = 106, N_RB_UL = 106, mu = 1;
|
||||
int srs_start_symbol = 13;
|
||||
int srs_comb_size = 0;
|
||||
int srs_comb_offset = 0;
|
||||
int srs_cyclic_shift = 0;
|
||||
int nb_symb_srs = 0;
|
||||
int i;
|
||||
int loglvl = OAILOG_WARNING;
|
||||
int print_perf = 0;
|
||||
int slot = 8;
|
||||
int frame = 1;
|
||||
cpuf = get_cpu_freq_GHz();
|
||||
double DS_TDL = .03;
|
||||
int threequarter_fs = 0;
|
||||
uint64_t SSB_positions = 0x01;
|
||||
uint16_t Nid_cell = 0;
|
||||
|
||||
if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == 0) {
|
||||
exit_fun("[NR_SRSSIM] Error, configuration module init failed\n");
|
||||
}
|
||||
|
||||
randominit();
|
||||
|
||||
/* initialize the sin-cos table */
|
||||
InitSinLUT();
|
||||
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "--:O:a:b:c:d:e:f:g:h:i:kl:m:n:p:s:u:y:z:A:B:C:H:PR:S:L:")) != -1) {
|
||||
/* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */
|
||||
/* with this opstring getopt returns 1 for non-option arguments, refer to 'man 3 getopt' */
|
||||
if (c == 1 || c == '-' || c == 'O')
|
||||
continue;
|
||||
|
||||
printf("handling optarg %c\n", c);
|
||||
switch (c) {
|
||||
case 'a':
|
||||
srs_start_symbol = atoi(optarg);
|
||||
AssertFatal(srs_start_symbol >= 8 && srs_start_symbol <= 13, "start_symbol %d is not in 8..13\n", srs_start_symbol);
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
nb_symb_srs = atoi(optarg);
|
||||
AssertFatal(nb_symb_srs == 1 || nb_symb_srs == 2 || nb_symb_srs == 4,
|
||||
"number of srs symbols %d is not 1,2,4\n",
|
||||
nb_symb_srs);
|
||||
nb_symb_srs >>= 1; // Value: 0 = 1 symbol, 1 = 2 symbols, 2 = 4 symbols
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
n_rnti = atoi(optarg);
|
||||
AssertFatal(n_rnti > 0 && n_rnti <= 65535, "Illegal n_rnti %x\n", n_rnti);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
delay = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
srs_comb_size = atoi(optarg);
|
||||
AssertFatal(srs_comb_size >= 0 && srs_comb_size < 2, "comb_size %d is not in 0 or 1\n", srs_comb_size);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
srs_comb_offset = atoi(optarg);
|
||||
if (srs_comb_size == 0) {
|
||||
AssertFatal(srs_comb_offset >= 0 && srs_comb_offset <= 1, "comb_offset %d is not in 0...1\n", srs_comb_offset);
|
||||
} else if (srs_comb_size == 1) {
|
||||
AssertFatal(srs_comb_offset >= 0 && srs_comb_offset <= 3, "comb_offset %d is not in 0...3\n", srs_comb_offset);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
|
||||
switch ((char)*optarg) {
|
||||
case 'A':
|
||||
channel_model = TDL_A;
|
||||
DS_TDL = 0.030; // 30 ns
|
||||
printf("Channel model: TDLA30\n");
|
||||
break;
|
||||
case 'B':
|
||||
channel_model = TDL_B;
|
||||
DS_TDL = 0.100; // 100ns
|
||||
printf("Channel model: TDLB100\n");
|
||||
break;
|
||||
case 'C':
|
||||
channel_model = TDL_C;
|
||||
DS_TDL = 0.300; // 300 ns
|
||||
printf("Channel model: TDLC300\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unsupported channel model!\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (optarg[1] == ',') {
|
||||
switch (optarg[2]) {
|
||||
case 'l':
|
||||
corr_level = CORR_LEVEL_LOW;
|
||||
break;
|
||||
case 'm':
|
||||
corr_level = CORR_LEVEL_MEDIUM;
|
||||
break;
|
||||
case 'h':
|
||||
corr_level = CORR_LEVEL_HIGH;
|
||||
break;
|
||||
default:
|
||||
printf("Invalid correlation level!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (optarg[3] == ',') {
|
||||
maxDoppler = atoi(&optarg[4]);
|
||||
printf("Maximum Doppler Frequency: %.0f Hz\n", maxDoppler);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
srs_cyclic_shift = atoi(optarg);
|
||||
if (srs_comb_size == 0) {
|
||||
AssertFatal(srs_cyclic_shift >= 0 && srs_cyclic_shift <= 7, "comb_shift %d is not in 0...7\n", srs_cyclic_shift);
|
||||
} else if (srs_comb_size == 1) {
|
||||
AssertFatal(srs_cyclic_shift >= 0 && srs_cyclic_shift <= 11, "comb_shift %d is not in 0...11\n", srs_cyclic_shift);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
printf("Setting threequarter_fs_flag\n");
|
||||
threequarter_fs = 1;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
n_trials = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
extended_prefix_flag = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
snr0 = atof(optarg);
|
||||
printf("Setting SNR0 to %f\n", snr0);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
mu = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
n_tx = atoi(optarg);
|
||||
if ((n_tx == 0) || (n_tx > 4)) {
|
||||
printf("Unsupported number of tx antennas %d\n", n_tx);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
n_rx = atoi(optarg);
|
||||
if ((n_rx == 0) || (n_rx > 8)) {
|
||||
printf("Unsupported number of rx antennas %d\n", n_rx);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
slot = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
N_RB_DL = atoi(optarg);
|
||||
N_RB_UL = N_RB_DL;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
snr1 = atof(optarg);
|
||||
snr1set = 1;
|
||||
printf("Setting SNR1 to %f\n", snr1);
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
print_perf = 1;
|
||||
cpu_meas_enabled = 1;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
loglvl = atoi(optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
case 'h':
|
||||
printf("%s -h(elp)\n", argv[0]);
|
||||
printf("-a SRS starting symbol (8 .. 13)\n");
|
||||
printf("-b SRS number of symbols (1, 2, 4)\n");
|
||||
printf("-c RNTI\n");
|
||||
printf("-d Introduce delay in terms of number of samples\n");
|
||||
printf("-e SRS comb size, 0 (comb size 2), 1 (comb size 4) \n");
|
||||
printf("-f SRS comb offset, 0 .. 1 (comb size 2), 0 .. 3 (comb size 4) \n");
|
||||
printf(
|
||||
"-g Channel model configuration. Arguments list: Number of arguments = 3, {Channel model: [A] TDLA30, [B] TDLB100, [C] "
|
||||
"TDLC300}, {Correlation: [l] Low, [m] Medium, [h] High}, {Maximum Doppler shift} e.g. -g A,l,10\n");
|
||||
printf("-h This message\n");
|
||||
printf("-i SRS cyclic shift, 0 .. 7 (comb size 2), 0 .. 11 (comb size 4) \n");
|
||||
printf("-k 3/4 sampling\n");
|
||||
printf("-n Number of trials to simulate\n");
|
||||
printf("-p Use extended prefix mode\n");
|
||||
printf("-s Starting SNR, runs from SNR0 to SNR0 + 10 dB if ending SNR isn't given\n");
|
||||
printf("-S Ending SNR, runs from SNR0 to SNR1\n");
|
||||
printf("-u Set the numerology\n");
|
||||
printf("-y Number of TX antennas used at UE\n");
|
||||
printf("-z Number of RX antennas used at gNB\n");
|
||||
printf("-H Slot number\n");
|
||||
printf("-L <log level, 0(errors), 1(warning), 2(info) 3(debug) 4 (trace)>\n");
|
||||
printf("-P Print SRS performances\n");
|
||||
printf("-R Maximum number of available resorce blocks (N_RB_DL)\n");
|
||||
exit(-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
logInit();
|
||||
set_glog(loglvl);
|
||||
|
||||
int ret = 1;
|
||||
|
||||
if (snr1set == 0)
|
||||
snr1 = snr0 + 10;
|
||||
|
||||
double sampling_rate, tx_bandwidth, rx_bandwidth;
|
||||
uint32_t samples;
|
||||
get_samplerate_and_bw(mu, N_RB_DL, threequarter_fs, &sampling_rate, &samples, &tx_bandwidth, &rx_bandwidth);
|
||||
|
||||
// Initialize gNB
|
||||
gNB = calloc_or_fail(1, sizeof(PHY_VARS_gNB));
|
||||
gNB->ofdm_offset_divisor = UINT_MAX;
|
||||
gNB->RU_list[0] = calloc_or_fail(1, sizeof(**gNB->RU_list));
|
||||
gNB->RU_list[0]->rfdevice.openair0_cfg = openair0_cfg;
|
||||
|
||||
NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
|
||||
fp->N_RB_DL = N_RB_DL;
|
||||
fp->N_RB_UL = N_RB_UL;
|
||||
fp->Ncp = extended_prefix_flag ? EXTENDED : NORMAL;
|
||||
fp->nb_antennas_tx = n_tx;
|
||||
fp->nb_antennas_rx = n_rx;
|
||||
fp->threequarter_fs = threequarter_fs;
|
||||
nr_phy_config_request_sim(gNB, N_RB_UL, N_RB_UL, mu, Nid_cell, SSB_positions);
|
||||
printf("dl freq %" PRIu64 " , ul freq %" PRIu64 " \n", fp->dl_CarrierFreq, fp->ul_CarrierFreq);
|
||||
do_tdd_config_sim(gNB, mu);
|
||||
phy_init_nr_gNB(gNB);
|
||||
|
||||
// Initialize UE
|
||||
UE = calloc_or_fail(1, sizeof(PHY_VARS_NR_UE));
|
||||
memcpy(&UE->frame_parms, fp, sizeof(NR_DL_FRAME_PARMS)); // setting same frame parameters as gNB
|
||||
|
||||
/* RU handles rxdataF, and gNB just has a pointer. Here, we don't have an RU,
|
||||
* so we need to allocate that memory as well. First index in rxdataF[0] index refers to beams*/
|
||||
for (i = 0; i < n_rx; i++)
|
||||
gNB->common_vars.rxdataF[0][i] = malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t));
|
||||
|
||||
/* no RU: need to have rxdata */
|
||||
c16_t **rxdata;
|
||||
rxdata = malloc_or_fail(n_rx * sizeof(*rxdata));
|
||||
for (i = 0; i < n_rx; i++)
|
||||
rxdata[i] = malloc16_clear(fp->samples_per_frame * sizeof(c16_t));
|
||||
|
||||
/* no memory allocated for UE common_vars: need to have txdata and txdataF */
|
||||
c16_t **txdata;
|
||||
txdata = malloc_or_fail(n_tx * sizeof(*txdata));
|
||||
for (i = 0; i < n_tx; i++)
|
||||
txdata[i] = malloc16_clear(fp->samples_per_frame * sizeof(c16_t));
|
||||
|
||||
c16_t **txdataF;
|
||||
txdataF = malloc_or_fail(n_tx * sizeof(*txdataF));
|
||||
for (i = 0; i < n_tx; i++)
|
||||
txdataF[i] = malloc16_clear(fp->samples_per_frame_wCP * sizeof(c16_t));
|
||||
|
||||
// Configure channel model
|
||||
UE2gNB = new_channel_desc_scm(n_tx,
|
||||
n_rx,
|
||||
channel_model,
|
||||
sampling_rate / 1e6,
|
||||
fp->ul_CarrierFreq,
|
||||
tx_bandwidth,
|
||||
DS_TDL,
|
||||
maxDoppler,
|
||||
corr_level,
|
||||
0,
|
||||
delay,
|
||||
0,
|
||||
0);
|
||||
|
||||
if (UE2gNB == NULL) {
|
||||
printf("Problem generating channel model. Exiting.\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Allocate memory to intermediate variables to apply channel
|
||||
int slot_length = get_samples_per_slot(slot, fp);
|
||||
|
||||
s_re = malloc_or_fail(n_tx * sizeof(double *));
|
||||
s_im = malloc_or_fail(n_tx * sizeof(double *));
|
||||
r_re = malloc_or_fail(n_rx * sizeof(double *));
|
||||
r_im = malloc_or_fail(n_rx * sizeof(double *));
|
||||
|
||||
for (int aatx = 0; aatx < n_tx; aatx++) {
|
||||
s_re[aatx] = calloc_or_fail(1, slot_length * sizeof(double));
|
||||
s_im[aatx] = calloc_or_fail(1, slot_length * sizeof(double));
|
||||
}
|
||||
|
||||
for (int aarx = 0; aarx < n_rx; aarx++) {
|
||||
r_re[aarx] = calloc_or_fail(1, slot_length * sizeof(double));
|
||||
r_im[aarx] = calloc_or_fail(1, slot_length * sizeof(double));
|
||||
}
|
||||
|
||||
//----------- configure SRS ----------------------------
|
||||
long locationAndBandwidth = PRBalloc_to_locationandbandwidth(N_RB_DL, 0);
|
||||
|
||||
// Configure SRS parameters at gNB
|
||||
const uint16_t m_SRS[64] = {4, 8, 12, 16, 16, 20, 24, 24, 28, 32, 36, 40, 48, 48, 52, 56,
|
||||
60, 64, 72, 72, 76, 80, 88, 96, 96, 104, 112, 120, 120, 120, 128, 128,
|
||||
128, 132, 136, 144, 144, 144, 144, 152, 160, 160, 160, 168, 176, 184, 192, 192,
|
||||
192, 192, 208, 216, 224, 240, 240, 240, 240, 256, 256, 256, 264, 272, 272, 272};
|
||||
nfapi_nr_srs_pdu_t srs_pdu = {.rnti = n_rnti,
|
||||
.bwp_size = NRRIV2BW(locationAndBandwidth, 275),
|
||||
.bwp_start = NRRIV2PRBOFFSET(locationAndBandwidth, 275),
|
||||
.subcarrier_spacing = fp->numerology_index,
|
||||
.cyclic_prefix = extended_prefix_flag,
|
||||
.num_ant_ports = n_tx == 4 ? 2
|
||||
: n_tx == 2 ? 1
|
||||
: 0,
|
||||
.num_symbols = nb_symb_srs,
|
||||
.num_repetitions = 0, // Value: 0 = 1, 1 = 2, 2 = 4
|
||||
.time_start_position = fp->symbols_per_slot - 1 - srs_start_symbol,
|
||||
.bandwidth_index = 0,
|
||||
.config_index = rrc_get_max_nr_csrs(srs_pdu.bwp_size, srs_pdu.bandwidth_index),
|
||||
.sequence_id = 40,
|
||||
.comb_size = srs_comb_size,
|
||||
.comb_offset = srs_comb_offset,
|
||||
.cyclic_shift = srs_cyclic_shift,
|
||||
.frequency_position = 0,
|
||||
.frequency_shift = 0,
|
||||
.frequency_hopping = 0,
|
||||
.group_or_sequence_hopping = 0,
|
||||
.resource_type = NR_SRS_Resource__resourceType_PR_periodic,
|
||||
.t_srs = 1,
|
||||
.t_offset = 0,
|
||||
.srs_parameters_v4.srs_bandwidth_size = m_SRS[srs_pdu.config_index],
|
||||
.srs_parameters_v4.usage = 1 << NR_SRS_ResourceSet__usage_codebook,
|
||||
.srs_parameters_v4.report_type[0] = 1,
|
||||
.srs_parameters_v4.iq_representation = 1,
|
||||
.srs_parameters_v4.prg_size = 1,
|
||||
.srs_parameters_v4.num_total_ue_antennas = 1 << srs_pdu.num_ant_ports,
|
||||
.beamforming.num_prgs = m_SRS[srs_pdu.config_index],
|
||||
.beamforming.prg_size = 1};
|
||||
|
||||
gNB->srs->srs_pdu = srs_pdu;
|
||||
gNB->srs->active = true;
|
||||
gNB->srs->beam_nb = 0;
|
||||
gNB->srs->frame = frame;
|
||||
gNB->srs->slot = slot;
|
||||
|
||||
// Configure SRS parameters at UE
|
||||
fapi_nr_ul_config_srs_pdu srs_config_pdu = {.rnti = srs_pdu.rnti,
|
||||
.bwp_size = srs_pdu.bwp_size,
|
||||
.bwp_start = srs_pdu.bwp_start,
|
||||
.subcarrier_spacing = srs_pdu.subcarrier_spacing,
|
||||
.cyclic_prefix = srs_pdu.cyclic_prefix,
|
||||
.num_ant_ports = srs_pdu.num_ant_ports,
|
||||
.num_symbols = srs_pdu.num_symbols,
|
||||
.num_repetitions = srs_pdu.num_repetitions,
|
||||
.time_start_position = srs_pdu.time_start_position,
|
||||
.bandwidth_index = srs_pdu.bandwidth_index,
|
||||
.config_index = srs_pdu.config_index,
|
||||
.sequence_id = srs_pdu.sequence_id,
|
||||
.comb_size = srs_pdu.comb_size,
|
||||
.comb_offset = srs_pdu.comb_offset,
|
||||
.cyclic_shift = srs_pdu.cyclic_shift,
|
||||
.frequency_position = srs_pdu.frequency_position,
|
||||
.frequency_shift = srs_pdu.frequency_shift,
|
||||
.frequency_hopping = srs_pdu.frequency_hopping,
|
||||
.group_or_sequence_hopping = srs_pdu.group_or_sequence_hopping,
|
||||
.resource_type = srs_pdu.resource_type,
|
||||
.t_srs = srs_pdu.t_srs,
|
||||
.t_offset = srs_pdu.t_offset,
|
||||
.beamforming.num_prgs = srs_pdu.beamforming.num_prgs,
|
||||
.beamforming.prg_size = srs_pdu.beamforming.prg_size};
|
||||
|
||||
nr_phy_data_tx_t phy_data = {0};
|
||||
phy_data.srs_vars.active = true;
|
||||
phy_data.srs_vars.srs_config_pdu = srs_config_pdu;
|
||||
UE->nr_srs_info = malloc16_clear(sizeof(nr_srs_info_t));
|
||||
|
||||
//----------- UE TX SRS procedures ---------------------
|
||||
|
||||
UE_nr_rxtx_proc_t proc;
|
||||
proc.frame_rx = frame;
|
||||
proc.frame_tx = frame;
|
||||
proc.nr_slot_tx = slot;
|
||||
proc.nr_slot_rx = slot;
|
||||
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT] = {0};
|
||||
int slot_offset = get_samples_slot_timestamp(fp, slot);
|
||||
uint16_t ofdm_symbol_size = fp->ofdm_symbol_size;
|
||||
int slot_offsetF = (slot % RU_RX_SLOT_DEPTH) * fp->symbols_per_slot * ofdm_symbol_size;
|
||||
|
||||
c16_t *txF[n_tx];
|
||||
for (i = 0; i < n_tx; i++)
|
||||
txF[i] = txdataF[i] + slot_offsetF;
|
||||
|
||||
c16_t *txd[n_tx];
|
||||
for (i = 0; i < n_tx; i++)
|
||||
txd[i] = txdata[i] + slot_offset;
|
||||
|
||||
ue_srs_procedures_nr(UE, &proc, (c16_t **)txF, &phy_data, was_symbol_used);
|
||||
|
||||
//------------ TX rotation and OFDM Modulation --------------------------
|
||||
nr_tx_rotation_and_ofdm_mod(slot, fp, n_tx, txF, txd, link_type_ul, was_symbol_used, false);
|
||||
|
||||
//----------- Apply propagation channel and add noise ----------------------------
|
||||
|
||||
double ts = 1.0 / (fp->subcarrier_spacing * ofdm_symbol_size);
|
||||
|
||||
for (i = 0; i < slot_length; i++) {
|
||||
for (int aa = 0; aa < n_tx; aa++) {
|
||||
s_re[aa][i] = (double)txdata[aa][slot_offset + i].r;
|
||||
s_im[aa][i] = (double)txdata[aa][slot_offset + i].i;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute SRS symbol offset and length
|
||||
int symbol_offset = slot_offset;
|
||||
int abs_first_symbol = slot * fp->symbols_per_slot;
|
||||
int idx_sym;
|
||||
for (idx_sym = abs_first_symbol; idx_sym < abs_first_symbol + srs_start_symbol; idx_sym++)
|
||||
symbol_offset += (idx_sym % (0x7 << fp->numerology_index)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0;
|
||||
|
||||
symbol_offset += ofdm_symbol_size * srs_start_symbol;
|
||||
int symbol_length = ofdm_symbol_size + (idx_sym % (0x7 << fp->numerology_index)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0;
|
||||
|
||||
// Compute transmitter energy level
|
||||
double txlev_sum = compute_tx_energy_level(txdata, n_tx, symbol_offset, symbol_length, n_trials);
|
||||
|
||||
for (SNR = snr0; SNR <= snr1 && !stop; SNR += snr_step) {
|
||||
varArray_t *table_rx = initVarArray(1000, sizeof(double));
|
||||
reset_meas(&gNB->rx_srs_stats);
|
||||
reset_meas(&gNB->generate_srs_stats);
|
||||
reset_meas(&gNB->get_srs_signal_stats);
|
||||
reset_meas(&gNB->srs_channel_estimation_stats);
|
||||
reset_meas(&gNB->srs_timing_advance_stats);
|
||||
|
||||
double sum_srs_snr = 0;
|
||||
int tao_ns_count = 0;
|
||||
for (trial = 0; trial < n_trials && !stop; trial++) {
|
||||
// Estimate noise power from the transmitter level and SNR
|
||||
double sigma = compute_noise_variance(txlev_sum, ofdm_symbol_size, srs_pdu.bwp_size, 1, SNR, n_trials);
|
||||
|
||||
//----------- Apply propagation channel ----------------------------
|
||||
multipath_channel(UE2gNB, s_re, s_im, r_re, r_im, slot_length, 0, (n_trials == 1) ? 1 : 0);
|
||||
|
||||
//----------- Add noise ----------------------------
|
||||
add_noise(rxdata,
|
||||
(const double **)r_re,
|
||||
(const double **)r_im,
|
||||
sigma, // noise power
|
||||
slot_length,
|
||||
slot_offset,
|
||||
ts,
|
||||
0, // delay
|
||||
0, // pdu_bit_map
|
||||
0, // PTRS_BITMAP,
|
||||
n_rx);
|
||||
|
||||
//----------- OFDM Demodulation and RX rotation--------------------------
|
||||
nr_ofdm_demod_and_rx_rotation(rxdata,
|
||||
gNB->common_vars.rxdataF[0],
|
||||
fp,
|
||||
n_rx,
|
||||
slot,
|
||||
slot_offsetF,
|
||||
link_type_ul,
|
||||
was_symbol_used);
|
||||
|
||||
//----------- UE RX SRS procedures ---------------------
|
||||
|
||||
start_meas(&gNB->rx_srs_stats);
|
||||
NR_gNB_SRS_t *srs = &gNB->srs[0];
|
||||
uint8_t N_symb_SRS = 1 << srs->srs_pdu.num_symbols;
|
||||
uint8_t N_ap = 1 << srs->srs_pdu.num_ant_ports;
|
||||
int16_t snr_per_rb[srs->srs_pdu.bwp_size];
|
||||
uint16_t timing_advance_offset;
|
||||
int16_t timing_advance_offset_nsec[n_rx];
|
||||
int srs_est;
|
||||
c16_t srs_estimated_channel_freq[n_rx][N_ap][ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32)));
|
||||
c16_t srs_estimated_channel_time[n_rx][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size] __attribute__((aligned(32)));
|
||||
|
||||
nr_srs_rx_procedures(gNB,
|
||||
frame,
|
||||
slot,
|
||||
n_rx,
|
||||
N_ap,
|
||||
N_symb_SRS,
|
||||
ofdm_symbol_size,
|
||||
srs,
|
||||
gNB->nr_srs_info[0],
|
||||
&srs_est,
|
||||
srs_estimated_channel_freq,
|
||||
srs_estimated_channel_time,
|
||||
snr_per_rb,
|
||||
&timing_advance_offset,
|
||||
timing_advance_offset_nsec);
|
||||
|
||||
sum_srs_snr += pow(10, (double)gNB->srs->snr / 10.0);
|
||||
|
||||
int16_t delay_ns = delay * 1e9 / (fp->samples_per_frame * 100);
|
||||
for (int ant_idx = 0; ant_idx < n_rx; ant_idx++) {
|
||||
if (n_trials == 1)
|
||||
printf("[RX ant %d] SRS estimated: TA offset %d, TA offset ns %d \n",
|
||||
ant_idx,
|
||||
timing_advance_offset,
|
||||
timing_advance_offset_nsec[ant_idx]);
|
||||
if (timing_advance_offset_nsec[ant_idx] == delay_ns)
|
||||
tao_ns_count++;
|
||||
}
|
||||
stop_meas(&gNB->rx_srs_stats);
|
||||
} // trail loop
|
||||
float tao_ns_rate = (float)tao_ns_count / (n_trials * n_rx);
|
||||
float SRS_SNR_dB = 10 * log10(sum_srs_snr / n_trials);
|
||||
printf("Actual SNR : %f, Estimated SNR from SRS %f (dB), TA offset success rate %f %%\n", SNR, SRS_SNR_dB, tao_ns_rate * 100);
|
||||
|
||||
if (print_perf == 1) {
|
||||
printf("\ngNB RX\n");
|
||||
printDistribution(&gNB->rx_srs_stats, table_rx, "RX SRS time");
|
||||
printStatIndent(&gNB->generate_srs_stats, "Generate SRS sequence time");
|
||||
printStatIndent(&gNB->get_srs_signal_stats, "Get SRS signal time");
|
||||
printStatIndent(&gNB->srs_channel_estimation_stats, "SRS channel estimation time");
|
||||
printStatIndent(&gNB->srs_timing_advance_stats, "SRS timing advance estimation time");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
free(table_rx);
|
||||
|
||||
int srs_ret = 1;
|
||||
if (SNR > 30 && SRS_SNR_dB > 30) {
|
||||
srs_ret = 0;
|
||||
} else if (SNR >= SRS_SNR_dB) {
|
||||
srs_ret = SRS_SNR_dB >= 0.7 * SNR ? 0 : 1;
|
||||
} else if (SRS_SNR_dB > SNR) {
|
||||
srs_ret = SNR >= 0.7 * SRS_SNR_dB ? 0 : 1;
|
||||
}
|
||||
|
||||
if (tao_ns_rate > 0.9 && srs_ret == 0) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
} // SNR loop
|
||||
|
||||
printf("*************\n");
|
||||
printf("SRS test %s\n", ret == 0 ? "OK" : "FAILED");
|
||||
printf("*************\n");
|
||||
|
||||
// free memory
|
||||
|
||||
for (i = 0; i < n_tx; i++) {
|
||||
free(s_re[i]);
|
||||
free(s_im[i]);
|
||||
free(txdata[i]);
|
||||
free(txdataF[i]);
|
||||
}
|
||||
free(s_re);
|
||||
free(s_im);
|
||||
free(txdata);
|
||||
free(txdataF);
|
||||
|
||||
for (i = 0; i < n_rx; i++) {
|
||||
free(r_re[i]);
|
||||
free(r_im[i]);
|
||||
free(rxdata[i]);
|
||||
free(gNB->common_vars.rxdataF[0][i]);
|
||||
}
|
||||
|
||||
free(r_re);
|
||||
free(r_im);
|
||||
free(rxdata);
|
||||
|
||||
phy_free_nr_gNB(gNB);
|
||||
free_channel_desc_scm(UE2gNB);
|
||||
free_and_zero(UE->nr_srs_info);
|
||||
free(gNB->RU_list[0]);
|
||||
free(UE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -281,7 +281,6 @@ int main(int argc, char *argv[])
|
||||
char *filename_csv = NULL;
|
||||
int i;
|
||||
double SNR, snr0 = -2.0, snr1 = 2.0;
|
||||
double sigma, sigma_dB;
|
||||
double snr_step = .2;
|
||||
uint8_t snr1set = 0;
|
||||
int slot = 8, frame = 1;
|
||||
@@ -308,7 +307,7 @@ int main(int argc, char *argv[])
|
||||
int Imcs = 9;
|
||||
uint8_t precod_nbr_layers = 1;
|
||||
int tx_offset;
|
||||
int32_t txlev_sum = 0, atxlev[4];
|
||||
double txlev_sum = 0;
|
||||
int start_rb = 0;
|
||||
int UE_id = 0;
|
||||
int print_perf = 0;
|
||||
@@ -1273,7 +1272,7 @@ int main(int argc, char *argv[])
|
||||
srs_pdu->subcarrier_spacing = gNB->frame_parms.subcarrier_spacing;
|
||||
srs_pdu->num_ant_ports = n_tx == 4 ? 2 : n_tx == 2 ? 1 : 0;
|
||||
srs_pdu->sequence_id = 40;
|
||||
srs_pdu->time_start_position = gNB->frame_parms.symbols_per_slot - 1;
|
||||
srs_pdu->time_start_position = 0;
|
||||
srs_pdu->config_index = rrc_get_max_nr_csrs(srs_pdu->bwp_size, srs_pdu->bandwidth_index);
|
||||
srs_pdu->resource_type = NR_SRS_Resource__resourceType_PR_periodic;
|
||||
srs_pdu->t_srs = 1;
|
||||
@@ -1371,6 +1370,7 @@ int main(int argc, char *argv[])
|
||||
srs_config_pdu->sequence_id = 40;
|
||||
srs_config_pdu->resource_type = NR_SRS_Resource__resourceType_PR_periodic;
|
||||
srs_config_pdu->t_srs = 1;
|
||||
srs_config_pdu->time_start_position = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (TBS / 8); i++)
|
||||
@@ -1400,36 +1400,22 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
///////////
|
||||
////////////////////////////////////////////////////
|
||||
// Compute transmitter energy level
|
||||
tx_offset = get_samples_slot_timestamp(&gNB->frame_parms, slot);
|
||||
txlev_sum = 0;
|
||||
for (int aa = 0; aa < UE->frame_parms.nb_antennas_tx; aa++) {
|
||||
atxlev[aa] =
|
||||
signal_energy((int32_t *)&UE->common_vars
|
||||
.txData[aa][tx_offset + 5 * gNB->frame_parms.ofdm_symbol_size
|
||||
+ 4 * gNB->frame_parms.nb_prefix_samples + gNB->frame_parms.nb_prefix_samples0],
|
||||
gNB->frame_parms.ofdm_symbol_size + gNB->frame_parms.nb_prefix_samples);
|
||||
|
||||
txlev_sum += atxlev[aa];
|
||||
|
||||
if (n_trials == 1)
|
||||
printf("txlev[%d] = %d (%f dB) txlev_sum %d\n", aa, atxlev[aa], 10 * log10((double)atxlev[aa]), txlev_sum);
|
||||
}
|
||||
int symbol_offset = tx_offset + 5 * gNB->frame_parms.ofdm_symbol_size + 4 * gNB->frame_parms.nb_prefix_samples
|
||||
+ gNB->frame_parms.nb_prefix_samples0;
|
||||
int symbol_length = gNB->frame_parms.ofdm_symbol_size + gNB->frame_parms.nb_prefix_samples;
|
||||
txlev_sum = compute_tx_energy_level(UE->common_vars.txData,
|
||||
UE->frame_parms.nb_antennas_tx,
|
||||
symbol_offset,
|
||||
symbol_length,
|
||||
n_trials);
|
||||
} else
|
||||
n_trials = 1;
|
||||
|
||||
if (input_fd == NULL) {
|
||||
// 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.
|
||||
sigma_dB =
|
||||
10 * log10((double)txlev_sum / precod_nbr_layers * ((double)gNB->frame_parms.ofdm_symbol_size / (12 * nb_rb))) - SNR;
|
||||
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((double)txlev_sum),
|
||||
(double)(double)gNB->frame_parms.ofdm_symbol_size / (12 * nb_rb));
|
||||
double sigma =
|
||||
compute_noise_variance(txlev_sum, gNB->frame_parms.ofdm_symbol_size, nb_rb, precod_nbr_layers, SNR, n_trials);
|
||||
|
||||
for (i = 0; i < slot_length; i++) {
|
||||
for (int aa = 0; aa < UE->frame_parms.nb_antennas_tx; aa++) {
|
||||
@@ -1460,26 +1446,20 @@ int main(int argc, char *argv[])
|
||||
UL_INFO.crc_ind.number_crcs = 0;
|
||||
UL_INFO.srs_ind.number_of_pdus = 0;
|
||||
|
||||
for(uint8_t symbol = 0; symbol < (gNB->frame_parms.Ncp == EXTENDED ? 12 : 14); symbol++) {
|
||||
for (int aa = 0; aa < gNB->frame_parms.nb_antennas_rx; aa++)
|
||||
nr_slot_fep_ul(&gNB->frame_parms,
|
||||
(int32_t *)rxdata[aa],
|
||||
(int32_t *)gNB->common_vars.rxdataF[0][aa],
|
||||
symbol,
|
||||
slot,
|
||||
0);
|
||||
}
|
||||
//----------- OFDM Demodulation and RX rotation--------------------------
|
||||
bool was_symbol_used[14] = {0};
|
||||
int offset = (slot & 3) * gNB->frame_parms.symbols_per_slot * gNB->frame_parms.ofdm_symbol_size;
|
||||
for (int aa = 0; aa < gNB->frame_parms.nb_antennas_rx; aa++) {
|
||||
const unsigned int max_symb = (gNB->frame_parms.Ncp == EXTENDED) ? 12 : 14;
|
||||
for (int sym = 0; sym < max_symb; sym++)
|
||||
apply_nr_rotation_symbol_RX(&gNB->frame_parms,
|
||||
gNB->common_vars.rxdataF[0][aa] + offset + sym * gNB->frame_parms.ofdm_symbol_size,
|
||||
gNB->frame_parms.symbol_rotation[1],
|
||||
gNB->frame_parms.N_RB_UL,
|
||||
slot,
|
||||
sym);
|
||||
for (int i = 0; i < 14; i++) {
|
||||
was_symbol_used[i] = true;
|
||||
}
|
||||
nr_ofdm_demod_and_rx_rotation(rxdata,
|
||||
gNB->common_vars.rxdataF[0],
|
||||
&gNB->frame_parms,
|
||||
gNB->frame_parms.nb_antennas_rx,
|
||||
slot,
|
||||
offset,
|
||||
link_type_ul,
|
||||
was_symbol_used);
|
||||
|
||||
ul_proc_error = phy_procedures_gNB_uespec_RX(gNB, frame, slot, &UL_INFO);
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ void __attribute__ ((no_sanitize_address)) multipath_channel(channel_desc_t *des
|
||||
|
||||
#ifdef DEBUG_CH
|
||||
|
||||
for (l = 0; l<(int)desc->channel_length; l++) {
|
||||
for (int l = 0; l<(int)desc->channel_length; l++) {
|
||||
printf("%p (%f,%f) ",desc->ch[0],desc->ch[0][l].x,desc->ch[0][l].y);
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ void __attribute__ ((no_sanitize_address)) multipath_channel(channel_desc_t *des
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CH
|
||||
for (l = 0; l<(int)desc->channel_length; l++) {
|
||||
for (int l = 0; l<(int)desc->channel_length; l++) {
|
||||
printf("ch[%i] = (%f, %f)\n", l, desc->ch[0][l].r, desc->ch[0][l].i);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -341,6 +341,27 @@ add_physim_test(physim.5g.nr_prachsim.test8 "15kHz SCS, 25 PRBs" nr_prachsim -a
|
||||
add_physim_test(physim.5g.nr_psbchsim.test1 "SLSS Search" nr_psbchsim -I)
|
||||
add_physim_test(physim.5g.nr_psbchsim.test2 "PSBCH TxRx" nr_psbchsim -n 30)
|
||||
|
||||
####################################################################################
|
||||
###### nr_srssim unit test ######
|
||||
####################################################################################
|
||||
|
||||
add_physim_test(physim.5g.nr_srssim.test1 "SRS: 30KHz SCS, 106 PRBs, ToA 24, Combsize 2" nr_srssim -n300 -R106 -s0 -S5 -y2 -z2 -d 24)
|
||||
add_physim_test(physim.5g.nr_srssim.test2 "SRS: 30KHz SCS, 106 PRBs, ToA 15, Combsize 2, Threequarter sampling" nr_srssim -n300 -R106 -s0 -S5 -y2 -z2 -d 15 -k)
|
||||
add_physim_test(physim.5g.nr_srssim.test3 "SRS: 30KHz SCS, 217 PRBs, ToA 8, Combsize 2" nr_srssim -n300 -R217 -s0 -S5 -y2 -z2 -d 8)
|
||||
add_physim_test(physim.5g.nr_srssim.test4 "SRS: 30KHz SCS, 273 PRBs, TOA 30, Combsize 2" nr_srssim -n300 -R273 -s0 -S5 -y2 -z2 -d 30)
|
||||
add_physim_test(physim.5g.nr_srssim.test5 "SRS: 30KHz SCS, 106 PRBs, ToA 16, Combsize 2, Cyclic shift 3" nr_srssim -n300 -R106 -s0 -S5 -y2 -z2 -d 16 -i 1)
|
||||
add_physim_test(physim.5g.nr_srssim.test6 "SRS: 30KHz SCS, 106 PRBs, ToA 23, Combsize 2, Comb offset 1" nr_srssim -n300 -R106 -s0 -S5 -y2 -z2 -d 23 -f 1)
|
||||
add_physim_test(physim.5g.nr_srssim.test7 "SRS: 30KHz SCS, 106 PRBs, ToA 8, Combsize 2, Symbol start 9" nr_srssim -n300 -R106 -s0 -S5 -y2 -z2 -d 8 -a 9)
|
||||
add_physim_test(physim.5g.nr_srssim.test8 "SRS: 120KHz SCS, 32 PRBs, ToA 19, Combsize 2" nr_srssim -n300 -R32 -s0 -S5 -y2 -z2 -d 19 -u 3)
|
||||
add_physim_test(physim.5g.nr_srssim.test9 "SRS: 30KHz SCS, 106 PRBs, ToA 11, Combsize 4" nr_srssim -n300 -R106 -s5 -S10 -y2 -z2 -d 11 -e 1)
|
||||
add_physim_test(physim.5g.nr_srssim.test10 "SRS: 30KHz SCS, 106 PRBs, ToA 7, Combsize 4, Comb offset 1" nr_srssim -n300 -R106 -s5 -S10 -y2 -z2 -d 7 -e 1 -f 1)
|
||||
add_physim_test(physim.5g.nr_srssim.test11 "SRS: 30KHz SCS, 106 PRBs, ToA 24, Combsize 2, SRS symbols 2, SRS start symbol 8" nr_srssim -n300 -R106 -s0 -S5 -y2 -z2 -d 24 -b 2 -a 8)
|
||||
add_physim_test(physim.5g.nr_srssim.test12 "SRS: 30KHz SCS, 106 PRBs, ToA 24, Combsize 2, SRS symbols 4, SRS start symbol 8" nr_srssim -n300 -R106 -s0 -S5 -y2 -z2 -d 24 -b 4 -a 8)
|
||||
add_physim_test(physim.5g.nr_srssim.test13 "SRS: 30KHz SCS, 106 PRBs, ToA 24, Combsize 4, SRS symbols 2, SRS start symbol 8" nr_srssim -n300 -R106 -s5 -S10 -y2 -z2 -d 24 -b 2 -e1 -a 8)
|
||||
add_physim_test(physim.5g.nr_srssim.test14 "SRS: 30KHz SCS, 106 PRBs, ToA 24, Combsize 4, SRS symbols 4, SRS start symbol 8" nr_srssim -n300 -R106 -s5 -S10 -y2 -z2 -d 24 -b 4 -e1 -a 8)
|
||||
add_physim_test(physim.5g.nr_srssim.test15 "SRS: 30KHz SCS, 217 PRBs, ToA 8, Combsize 2, SRS symbols 4, SRS start symbol 8" nr_srssim -n300 -R217 -s0 -S5 -y2 -z2 -d 8 -b 4 -a 8)
|
||||
add_physim_test(physim.5g.nr_srssim.test16 "SRS: 30KHz SCS, 106 PRBs, SNR 2 dB to 30 dB in steps of 5 dB, ToA 24, Combsize 2" nr_srssim -n300 -R106 -s2 -S30 -y2 -z2 -d 24)
|
||||
|
||||
####################################################################################
|
||||
###### offload-specific tests ######
|
||||
####################################################################################
|
||||
|
||||
@@ -428,7 +428,7 @@ static void nr_configure_srs(gNB_MAC_INST *nrmac,
|
||||
srs_pdu->num_ant_ports = srs_resource->nrofSRS_Ports;
|
||||
srs_pdu->num_symbols = srs_resource->resourceMapping.nrofSymbols;
|
||||
srs_pdu->num_repetitions = srs_resource->resourceMapping.repetitionFactor;
|
||||
srs_pdu->time_start_position = NR_NUMBER_OF_SYMBOLS_PER_SLOT - 1 - srs_resource->resourceMapping.startPosition;
|
||||
srs_pdu->time_start_position = srs_resource->resourceMapping.startPosition;
|
||||
srs_pdu->config_index = srs_resource->freqHopping.c_SRS;
|
||||
srs_pdu->sequence_id = srs_resource->sequenceId;
|
||||
srs_pdu->bandwidth_index = srs_resource->freqHopping.b_SRS;
|
||||
@@ -479,7 +479,8 @@ static void nr_configure_srs(gNB_MAC_INST *nrmac,
|
||||
AssertFatal(beam.idx >= 0, "Cannot allocate SRS in any available beam\n");
|
||||
uint16_t *vrb_map_UL = &nrmac->common_channels[CC_id].vrb_map_UL[beam.idx][buffer_index * MAX_BWP_SIZE];
|
||||
uint16_t num = 1 << srs_pdu->num_symbols; // 0,1,2 means 1,2,4 symbols, see 222.10.04 table 3-105
|
||||
uint16_t mask = SL_to_bitmap(srs_pdu->time_start_position, num);
|
||||
const uint8_t l0 = NR_NUMBER_OF_SYMBOLS_PER_SLOT - 1 - srs_pdu->time_start_position;
|
||||
uint16_t mask = SL_to_bitmap(l0, num);
|
||||
DevAssert(mask != 0);
|
||||
for (int i = 0; i < srs_pdu->bwp_size; ++i) {
|
||||
int rb = i + srs_pdu->bwp_start;
|
||||
|
||||
Reference in New Issue
Block a user