- remove hardcoded values - adapt gNB RRC code - adapt gNB MAC code - adapt physical simulators, where we put the hardcoded values that were everywhere else before; if there is a need for those simulators to get configurable values, more work is needed (but it's doubtful that it is needed)
1591 lines
62 KiB
C
1591 lines
62 KiB
C
/*
|
|
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The OpenAirInterface Software Alliance licenses this file to You under
|
|
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.openairinterface.org/?page_id=698
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*-------------------------------------------------------------------------------
|
|
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
|
* contact@openairinterface.org
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <math.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "common/utils/assertions.h"
|
|
#include "common/utils/nr/nr_common.h"
|
|
#include "common/utils/var_array.h"
|
|
#include "executables/nr-uesoftmodem.h"
|
|
#include "executables/softmodem-common.h"
|
|
#include "LAYER2/NR_MAC_UE/mac_defs.h"
|
|
#include "LAYER2/NR_MAC_UE/mac_proto.h"
|
|
#include "LAYER2/NR_MAC_gNB/mac_proto.h"
|
|
#include "LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h"
|
|
#include "LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
|
|
#include "LAYER2/NR_MAC_gNB/nr_radio_config.h"
|
|
#include "NR_BCCH-BCH-Message.h"
|
|
#include "NR_BWP-Downlink.h"
|
|
#include "NR_CellGroupConfig.h"
|
|
#include "NR_MAC_COMMON/nr_mac.h"
|
|
#include "NR_MAC_COMMON/nr_mac_common.h"
|
|
#include "NR_PHY_INTERFACE/NR_IF_Module.h"
|
|
#include "NR_ReconfigurationWithSync.h"
|
|
#include "NR_ServingCellConfig.h"
|
|
#include "NR_SetupRelease.h"
|
|
#include "NR_UE_PHY_INTERFACE/NR_IF_Module.h"
|
|
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
|
|
#include "PHY/INIT/nr_phy_init.h"
|
|
#include "PHY/MODULATION/modulation_common.h"
|
|
#include "PHY/NR_REFSIG/ptrs_nr.h"
|
|
#include "PHY/NR_TRANSPORT/nr_dlsch.h"
|
|
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
|
|
#include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h"
|
|
#include "PHY/TOOLS/tools_defs.h"
|
|
#include "PHY/defs_RU.h"
|
|
#include "PHY/defs_gNB.h"
|
|
#include "PHY/defs_nr_UE.h"
|
|
#include "PHY/defs_nr_common.h"
|
|
#include "PHY/impl_defs_nr.h"
|
|
#include "PHY/phy_vars_nr_ue.h"
|
|
#include "SCHED_NR/fapi_nr_l1.h"
|
|
#include "SCHED_NR/sched_nr.h"
|
|
#include "SCHED_NR_UE/defs.h"
|
|
#include "SCHED_NR_UE/fapi_nr_ue_l1.h"
|
|
#include "T.h"
|
|
#include "asn_internal.h"
|
|
#include "assertions.h"
|
|
#include "common/config/config_load_configmodule.h"
|
|
#include "common/ngran_types.h"
|
|
#include "common/ran_context.h"
|
|
#include "common/utils/T/T.h"
|
|
#include "common/utils/nr/nr_common.h"
|
|
#include "common/utils/var_array.h"
|
|
#include "common_lib.h"
|
|
#include "e1ap_messages_types.h"
|
|
#include "fapi_nr_ue_interface.h"
|
|
#include "nfapi_interface.h"
|
|
#include "nfapi_nr_interface.h"
|
|
#include "nfapi_nr_interface_scf.h"
|
|
#include "nr_ue_phy_meas.h"
|
|
#include "oai_asn1.h"
|
|
#include "openair1/SIMULATION/NR_PHY/nr_unitary_defs.h"
|
|
#include "openair1/SIMULATION/TOOLS/sim.h"
|
|
#include "thread-pool.h"
|
|
#include "time_meas.h"
|
|
#include "utils.h"
|
|
#define inMicroS(a) (((double)(a))/(get_cpu_freq_GHz()*1000.0))
|
|
#include "SIMULATION/LTE_PHY/common_sim.h"
|
|
|
|
const char *__asan_default_options()
|
|
{
|
|
/* don't do leak checking in nr_ulsim, not finished yet */
|
|
return "detect_leaks=0";
|
|
}
|
|
|
|
PHY_VARS_gNB *gNB;
|
|
PHY_VARS_NR_UE *UE;
|
|
RAN_CONTEXT_t RC;
|
|
int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
|
|
double cpuf;
|
|
char *uecap_file;
|
|
|
|
//uint8_t nfapi_mode = 0;
|
|
uint64_t downlink_frequency[MAX_NUM_CCs][4];
|
|
THREAD_STRUCT thread_struct;
|
|
nfapi_ue_release_request_body_t release_rntis;
|
|
//Fixme: Uniq dirty DU instance, by global var, datamodel need better management
|
|
instance_t DUuniqInstance=0;
|
|
instance_t CUuniqInstance=0;
|
|
|
|
// NTN cellSpecificKoffset-r17, but in slots for DL SCS
|
|
unsigned int NTN_UE_Koffset = 0;
|
|
|
|
void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t key[32], uint8_t *key_ng_ran_star)
|
|
{
|
|
}
|
|
|
|
/* Function to set or overwrite PTRS DL RRC parameters */
|
|
static void rrc_config_dl_ptrs_params(NR_BWP_Downlink_t *bwp, long *ptrsNrb, long *ptrsMcs, long *epre_Ratio, long *reOffset)
|
|
{
|
|
int i=0;
|
|
NR_DMRS_DownlinkConfig_t *tmp = bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup;
|
|
// struct NR_SetupRelease_PTRS_DownlinkConfig *tmp=bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS;
|
|
/* check for memory allocation */
|
|
if (tmp->phaseTrackingRS == NULL) {
|
|
asn1cCalloc(tmp->phaseTrackingRS, TrackingRS);
|
|
TrackingRS->present = NR_SetupRelease_PTRS_DownlinkConfig_PR_setup;
|
|
asn1cCalloc(TrackingRS->choice.setup, setup);
|
|
asn1cCalloc(setup->frequencyDensity, freqD);
|
|
/* Fill the given values */
|
|
for(i = 0; i < 2; i++) {
|
|
asn1cSequenceAdd(freqD->list, long, nbr);
|
|
*nbr = ptrsNrb[i];
|
|
}
|
|
asn1cCalloc(setup->timeDensity, timeD);
|
|
for(i = 0; i < 3; i++) {
|
|
asn1cSequenceAdd(timeD->list, long, mcs);
|
|
*mcs = ptrsMcs[i];
|
|
}
|
|
asn1cCallocOne(setup->epre_Ratio, epre_Ratio[0]);
|
|
asn1cCallocOne(setup->resourceElementOffset, reOffset[0]);
|
|
} else {
|
|
NR_PTRS_DownlinkConfig_t *TrackingRS = tmp->phaseTrackingRS->choice.setup;
|
|
for(i = 0; i < 2; i++) {
|
|
*TrackingRS->frequencyDensity->list.array[i] = ptrsNrb[i];
|
|
}
|
|
for(i = 0; i < 3; i++) {
|
|
*TrackingRS->timeDensity->list.array[i] = ptrsMcs[i];
|
|
}
|
|
*TrackingRS->epre_Ratio = epre_Ratio[0];
|
|
*TrackingRS->resourceElementOffset = reOffset[0];
|
|
}
|
|
}
|
|
|
|
int dummy_nr_ue_ul_indication(nr_uplink_indication_t *ul_info) { return(0); }
|
|
|
|
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(); }
|
|
|
|
int8_t nr_rrc_RA_succeeded(const module_id_t mod_id, const uint8_t gNB_index) {
|
|
return 0;
|
|
}
|
|
|
|
void nr_derive_key(int alg_type, uint8_t alg_id, const uint8_t key[32], uint8_t out[16])
|
|
{
|
|
(void)alg_type;
|
|
}
|
|
|
|
void processSlotTX(void *arg) {}
|
|
|
|
// needed for some functions
|
|
openair0_config_t openair0_cfg[MAX_CARDS];
|
|
void update_ptrs_config(NR_CellGroupConfig_t *secondaryCellGroup, uint16_t *rbSize, uint8_t *mcsIndex,int8_t *ptrs_arg);
|
|
void update_dmrs_config(NR_CellGroupConfig_t *scg, int8_t* dmrs_arg);
|
|
extern void fix_scd(NR_ServingCellConfig_t *scd);// forward declaration
|
|
|
|
/* specific dlsim DL preprocessor: uses rbStart/rbSize/mcs/nrOfLayers from command line of dlsim */
|
|
int g_mcsIndex = -1, g_mcsTableIdx = 0, g_rbStart = -1, g_rbSize = -1, g_nrOfLayers = 1, g_pmi = 0;
|
|
|
|
void nr_dlsim_preprocessor(module_id_t module_id, frame_t frame, slot_t slot)
|
|
{
|
|
NR_UE_info_t *UE_info = RC.nrmac[module_id]->UE_info.connected_ue_list[0];
|
|
AssertFatal(RC.nrmac[module_id]->UE_info.connected_ue_list[1] == NULL, "Only single UE allowed in dlsim\n");
|
|
NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl;
|
|
NR_UE_DL_BWP_t *current_BWP = &UE_info->current_DL_BWP;
|
|
NR_ServingCellConfigCommon_t *scc = RC.nrmac[0]->common_channels[0].ServingCellConfigCommon;
|
|
|
|
uint8_t nr_of_candidates = 0;
|
|
if (g_mcsIndex < 4) {
|
|
find_aggregation_candidates(&sched_ctrl->aggregation_level,
|
|
&nr_of_candidates,
|
|
sched_ctrl->search_space,8);
|
|
}
|
|
if (nr_of_candidates == 0) {
|
|
find_aggregation_candidates(&sched_ctrl->aggregation_level,
|
|
&nr_of_candidates,
|
|
sched_ctrl->search_space,4);
|
|
}
|
|
uint32_t Y = get_Y(sched_ctrl->search_space, slot, UE_info->rnti);
|
|
int CCEIndex = find_pdcch_candidate(RC.nrmac[module_id],
|
|
/* CC_id = */ 0,
|
|
sched_ctrl->aggregation_level,
|
|
nr_of_candidates,
|
|
0,
|
|
&sched_ctrl->sched_pdcch,
|
|
sched_ctrl->coreset,
|
|
Y);
|
|
AssertFatal(CCEIndex>=0, "%4d.%2d could not find CCE for DL DCI UE %d/RNTI %04x\n", frame, slot, 0, UE_info->rnti);
|
|
sched_ctrl->cce_index = CCEIndex;
|
|
|
|
NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch;
|
|
sched_pdsch->rbStart = g_rbStart;
|
|
sched_pdsch->rbSize = g_rbSize;
|
|
sched_pdsch->mcs = g_mcsIndex;
|
|
sched_pdsch->nrOfLayers = g_nrOfLayers;
|
|
sched_pdsch->pm_index = g_pmi;
|
|
/* the following might override the table that is mandated by RRC
|
|
* configuration */
|
|
current_BWP->mcsTableIdx = g_mcsTableIdx;
|
|
sched_pdsch->time_domain_allocation = get_dl_tda(RC.nrmac[module_id], slot);
|
|
AssertFatal(sched_pdsch->time_domain_allocation >= 0,"Unable to find PDSCH time domain allocation in list\n");
|
|
|
|
sched_pdsch->tda_info = get_dl_tda_info(current_BWP,
|
|
sched_ctrl->search_space->searchSpaceType->present,
|
|
sched_pdsch->time_domain_allocation,
|
|
NR_MIB__dmrs_TypeA_Position_pos2,
|
|
1,
|
|
TYPE_C_RNTI_,
|
|
sched_ctrl->coreset->controlResourceSetId,
|
|
false);
|
|
|
|
sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc,
|
|
current_BWP,
|
|
&sched_pdsch->tda_info,
|
|
sched_pdsch->nrOfLayers);
|
|
|
|
sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx);
|
|
sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx);
|
|
sched_pdsch->tb_size = nr_compute_tbs(sched_pdsch->Qm,
|
|
sched_pdsch->R,
|
|
sched_pdsch->rbSize,
|
|
sched_pdsch->tda_info.nrOfSymbols,
|
|
sched_pdsch->dmrs_parms.N_PRB_DMRS * sched_pdsch->dmrs_parms.N_DMRS_SLOT,
|
|
0 /* N_PRB_oh, 0 for initialBWP */,
|
|
0 /* tb_scaling */,
|
|
sched_pdsch->nrOfLayers) >> 3;
|
|
|
|
/* the simulator assumes the HARQ PID is equal to the slot number */
|
|
sched_pdsch->dl_harq_pid = slot;
|
|
|
|
/* The scheduler uses lists to track whether a HARQ process is
|
|
* free/busy/awaiting retransmission, and updates the HARQ process states.
|
|
* However, in the simulation, we never get ack or nack for any HARQ process,
|
|
* thus the list and HARQ states don't match what the scheduler expects.
|
|
* Therefore, below lines just "repair" everything so that the scheduler
|
|
* won't remark that there is no HARQ feedback */
|
|
sched_ctrl->feedback_dl_harq.head = -1; // always overwrite feedback HARQ process
|
|
if (sched_ctrl->harq_processes[slot].round == 0) // depending on round set in simulation ...
|
|
add_front_nr_list(&sched_ctrl->available_dl_harq, slot); // ... make PID available
|
|
else
|
|
add_front_nr_list(&sched_ctrl->retrans_dl_harq, slot); // ... make PID retransmission
|
|
sched_ctrl->harq_processes[slot].is_waiting = false;
|
|
AssertFatal(sched_pdsch->rbStart >= 0, "invalid rbStart %d\n", sched_pdsch->rbStart);
|
|
AssertFatal(sched_pdsch->rbSize > 0, "invalid rbSize %d\n", sched_pdsch->rbSize);
|
|
AssertFatal(sched_pdsch->mcs >= 0, "invalid mcs %d\n", sched_pdsch->mcs);
|
|
AssertFatal(current_BWP->mcsTableIdx >= 0 && current_BWP->mcsTableIdx <= 2, "invalid mcsTableIdx %d\n", current_BWP->mcsTableIdx);
|
|
}
|
|
|
|
nrUE_params_t nrUE_params;
|
|
|
|
nrUE_params_t *get_nrUE_params(void) {
|
|
return &nrUE_params;
|
|
}
|
|
|
|
|
|
void validate_input_pmi(nfapi_nr_config_request_scf_t *gNB_config,
|
|
nr_pdsch_AntennaPorts_t pdsch_AntennaPorts,
|
|
int nrOfLayers,
|
|
int pmi)
|
|
{
|
|
if (pmi == 0)
|
|
return;
|
|
|
|
nfapi_nr_pm_pdu_t *pmi_pdu = &gNB_config->pmi_list.pmi_pdu[pmi - 1]; // pmi 0 is identity matrix
|
|
AssertFatal(pmi == pmi_pdu->pm_idx, "PMI %d doesn't match to the one in precoding matrix %d\n", pmi, pmi_pdu->pm_idx);
|
|
AssertFatal(nrOfLayers == pmi_pdu->numLayers, "Number of layers %d doesn't match to the one in precoding matrix %d for PMI %d\n",
|
|
nrOfLayers, pmi_pdu->numLayers, pmi);
|
|
int num_antenna_ports = pdsch_AntennaPorts.N1 * pdsch_AntennaPorts.N2 * pdsch_AntennaPorts.XP;
|
|
AssertFatal(num_antenna_ports == pmi_pdu->num_ant_ports, "Configured antenna ports %d does not match precoding matrix AP size %d for PMI %d\n",
|
|
num_antenna_ports, pmi_pdu->num_ant_ports, pmi);
|
|
}
|
|
|
|
|
|
configmodule_interface_t *uniqCfg = NULL;
|
|
int main(int argc, char **argv)
|
|
{
|
|
stop = false;
|
|
__attribute__((unused)) struct sigaction oldaction;
|
|
sigaction(SIGINT, &sigint_action, &oldaction);
|
|
|
|
FILE *csv_file = NULL;
|
|
char *filename_csv = NULL;
|
|
setbuf(stdout, NULL);
|
|
int c;
|
|
int i,aa;//,l;
|
|
double sigma2, sigma2_dB=10, SNR, snr0=-2.0, snr1=2.0;
|
|
uint8_t snr1set=0;
|
|
float effRate;
|
|
//float psnr;
|
|
float eff_tp_check = 0.7;
|
|
uint32_t TBS = 0;
|
|
c16_t **txdata;
|
|
double **s_re,**s_im,**r_re,**r_im;
|
|
//double iqim = 0.0;
|
|
//unsigned char pbch_pdu[6];
|
|
// int sync_pos, sync_pos_slot;
|
|
// FILE *rx_frame_file;
|
|
FILE *output_fd = NULL;
|
|
//uint8_t write_output_file=0;
|
|
//int result;
|
|
//int freq_offset;
|
|
// int subframe_offset;
|
|
// char fname[40], vname[40];
|
|
int trial, n_trials = 1, n_false_positive = 0;
|
|
//int n_errors2, n_alamouti;
|
|
uint8_t n_tx=1,n_rx=1;
|
|
uint8_t round;
|
|
uint8_t num_rounds = 4;
|
|
char gNBthreads[128]="n";
|
|
|
|
channel_desc_t *gNB2UE;
|
|
//uint32_t nsymb,tx_lev,tx_lev1 = 0,tx_lev2 = 0;
|
|
//uint8_t extended_prefix_flag=0;
|
|
//int8_t interf1=-21,interf2=-21;
|
|
|
|
FILE *input_fd=NULL,*pbch_file_fd=NULL;
|
|
//char input_val_str[50],input_val_str2[50];
|
|
|
|
//uint8_t frame_mod4,num_pdcch_symbols = 0;
|
|
|
|
SCM_t channel_model = AWGN; // AWGN Rayleigh1 Rayleigh1_anticorr;
|
|
double DS_TDL = .03;
|
|
int delay = 0;
|
|
|
|
//double pbch_sinr;
|
|
//int pbch_tx_ant;
|
|
int N_RB_DL=106,mu=1;
|
|
|
|
//unsigned char frame_type = 0;
|
|
|
|
int frame=1,slot=1;
|
|
int frame_length_complex_samples;
|
|
//int frame_length_complex_samples_no_prefix;
|
|
NR_DL_FRAME_PARMS *frame_parms;
|
|
UE_nr_rxtx_proc_t UE_proc;
|
|
NR_Sched_Rsp_t *Sched_INFO;
|
|
gNB_MAC_INST *gNB_mac;
|
|
NR_UE_MAC_INST_t *UE_mac;
|
|
int cyclic_prefix_type = NFAPI_CP_NORMAL;
|
|
int loglvl=OAILOG_WARNING;
|
|
|
|
//float target_error_rate = 0.01;
|
|
cpuf = get_cpu_freq_GHz();
|
|
int8_t enable_ptrs = 0;
|
|
int8_t modify_dmrs = 0;
|
|
|
|
int8_t dmrs_arg[3] = {-1,-1,-1};// Invalid values
|
|
/* L_PTRS = ptrs_arg[0], K_PTRS = ptrs_arg[1] */
|
|
int8_t ptrs_arg[2] = {-1,-1};// Invalid values
|
|
|
|
uint16_t ptrsRePerSymb = 0;
|
|
uint16_t pdu_bit_map = 0x0;
|
|
uint16_t dlPtrsSymPos = 0;
|
|
uint16_t ptrsSymbPerSlot = 0;
|
|
uint16_t rbSize = 106;
|
|
uint8_t mcsIndex = 9;
|
|
uint8_t dlsch_threads = 0;
|
|
int chest_type[2] = {0};
|
|
uint8_t max_ldpc_iterations = 5;
|
|
if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == 0) {
|
|
exit_fun("[NR_DLSIM] Error, configuration module init failed\n");
|
|
}
|
|
|
|
randominit(0);
|
|
|
|
int print_perf = 0;
|
|
|
|
FILE *scg_fd=NULL;
|
|
|
|
while ((c = getopt(argc, argv, "--:O:f:hA:p:f:g:i:n:s:S:t:v:x:y:z:o:H:M:N:F:GR:d:PI:L:a:b:e:m:w:T:U:q:X:Y:Z:")) != -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 'f':
|
|
scg_fd = fopen(optarg,"r");
|
|
|
|
if (scg_fd==NULL) {
|
|
printf("Error opening %s\n",optarg);
|
|
exit(-1);
|
|
}
|
|
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);
|
|
}
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
for(i=0; i < atoi(optarg); i++){
|
|
chest_type[i] = atoi(argv[optind++]);
|
|
}
|
|
break;
|
|
|
|
case 'n':
|
|
n_trials = atoi(optarg);
|
|
break;
|
|
|
|
case 's':
|
|
snr0 = atof(optarg);
|
|
printf("Setting SNR0 to %f\n",snr0);
|
|
break;
|
|
|
|
case 'S':
|
|
snr1 = atof(optarg);
|
|
snr1set=1;
|
|
printf("Setting SNR1 to %f\n",snr1);
|
|
break;
|
|
|
|
case 'x':
|
|
g_nrOfLayers = atoi(optarg);
|
|
|
|
if ((g_nrOfLayers == 0) || (g_nrOfLayers > 4)) {
|
|
printf("Unsupported nr Of Layers %d\n", g_nrOfLayers);
|
|
exit(-1);
|
|
}
|
|
break;
|
|
|
|
case 'p':
|
|
g_pmi = atoi(optarg);
|
|
break;
|
|
|
|
case 'v':
|
|
num_rounds = atoi(optarg);
|
|
|
|
AssertFatal(num_rounds > 0 && num_rounds < 16, "Unsupported number of rounds %d, should be in [1,16]\n", num_rounds);
|
|
break;
|
|
|
|
case 'y':
|
|
n_tx=atoi(optarg);
|
|
|
|
if ((n_tx==0) || (n_tx>4)) {//extend gNB to support 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>4)) {//extend UE to support n_tx = 4
|
|
printf("Unsupported number of rx antennas %d\n",n_rx);
|
|
exit(-1);
|
|
}
|
|
|
|
break;
|
|
|
|
case 'R':
|
|
N_RB_DL = atoi(optarg);
|
|
break;
|
|
|
|
case 'F':
|
|
input_fd = fopen(optarg,"r");
|
|
|
|
if (input_fd==NULL) {
|
|
printf("Problem with filename %s\n",optarg);
|
|
exit(-1);
|
|
}
|
|
|
|
break;
|
|
|
|
case 'P':
|
|
print_perf=1;
|
|
cpu_meas_enabled = 1;
|
|
break;
|
|
|
|
case 'I':
|
|
max_ldpc_iterations = atoi(optarg);
|
|
break;
|
|
|
|
case 'L':
|
|
loglvl = atoi(optarg);
|
|
break;
|
|
|
|
case 'a':
|
|
g_rbStart = atoi(optarg);
|
|
break;
|
|
|
|
case 'b':
|
|
g_rbSize = atoi(optarg);
|
|
break;
|
|
|
|
case 'd':
|
|
dlsch_threads = atoi(optarg);
|
|
break;
|
|
|
|
case 'e':
|
|
g_mcsIndex = atoi(optarg);
|
|
break;
|
|
|
|
case 'q':
|
|
g_mcsTableIdx = atoi(optarg);
|
|
break;
|
|
|
|
case 'm':
|
|
mu = atoi(optarg);
|
|
break;
|
|
|
|
case 't':
|
|
eff_tp_check = (float)atoi(optarg)/100;
|
|
break;
|
|
|
|
case 'w':
|
|
output_fd = fopen("txdata.dat", "w+");
|
|
break;
|
|
|
|
case 'T':
|
|
enable_ptrs=1;
|
|
for(i=0; i < atoi(optarg); i++) {
|
|
ptrs_arg[i] = atoi(argv[optind++]);
|
|
}
|
|
break;
|
|
|
|
case 'U':
|
|
modify_dmrs = 1;
|
|
for(i=0; i < atoi(optarg); i++) {
|
|
dmrs_arg[i] = atoi(argv[optind++]);
|
|
}
|
|
break;
|
|
|
|
case 'X':
|
|
strncpy(gNBthreads, optarg, sizeof(gNBthreads)-1);
|
|
gNBthreads[sizeof(gNBthreads)-1]=0;
|
|
break;
|
|
|
|
case 'Z' :
|
|
filename_csv = strdup(optarg);
|
|
AssertFatal(filename_csv != NULL, "strdup() error: errno %d\n", errno);
|
|
break;
|
|
|
|
case 'o':
|
|
delay = atoi(optarg);
|
|
break;
|
|
|
|
case 'H':
|
|
slot = atoi(optarg);
|
|
break;
|
|
|
|
default:
|
|
case 'h':
|
|
printf("%s -h(elp) -p(extended_prefix) -N cell_id -f output_filename -F input_filename -g channel_model -n n_frames -s snr0 -S snr1 -x transmission_mode -y TXant -z RXant -i Intefrence0 -j Interference1 -A interpolation_file -C(alibration offset dB) -N CellId\n",
|
|
argv[0]);
|
|
printf("-h This message\n");
|
|
printf("-L <log level, 0(errors), 1(warning), 2(analysis), 3(info), 4(debug), 5(trace)>\n");
|
|
//printf("-p Use extended prefix mode\n");
|
|
//printf("-d Use TDD\n");
|
|
printf("-n Number of frames to simulate\n");
|
|
printf("-s Starting SNR, runs from SNR0 to SNR0 + 5 dB. If n_frames is 1 then just SNR is simulated\n");
|
|
printf("-S Ending SNR, runs from SNR0 to SNR1\n");
|
|
//printf("-t Delay spread for multipath channel\n");
|
|
printf("-g Channel model: [A] TDLA30, [B] TDLB100, [C] TDLC300, e.g. -g A\n");
|
|
printf("-o Introduce delay in terms of number of samples\n");
|
|
printf("-y Number of TX antennas used in gNB\n");
|
|
printf("-z Number of RX antennas used in UE\n");
|
|
printf("-x Num of layer for PDSCH\n");
|
|
printf("-p Precoding matrix index\n");
|
|
printf("-i Change channel estimation technique. Arguments list: Frequency domain {0:Linear interpolation, 1:PRB based averaging}, Time domain {0:Estimates of last DMRS symbol, 1:Average of DMRS symbols}\n");
|
|
//printf("-j Relative strength of second intefering gNB (in dB) - cell_id mod 3 = 2\n");
|
|
printf("-R N_RB_DL\n");
|
|
printf("-O oversampling factor (1,2,4,8,16)\n");
|
|
printf("-A Interpolation_filname Run with Abstraction to generate Scatter plot using interpolation polynomial in file\n");
|
|
//printf("-C Generate Calibration information for Abstraction (effective SNR adjustment to remove Pe bias w.r.t. AWGN)\n");
|
|
printf("-f raw file containing RRC configuration (generated by gNB)\n");
|
|
printf("-F Input filename (.txt format) for RX conformance testing\n");
|
|
printf("-a Start PRB for PDSCH\n");
|
|
printf("-b Number of PRB for PDSCH\n");
|
|
printf("-d number of dlsch threads, 0: no dlsch parallelization\n");
|
|
printf("-e MSC index\n");
|
|
printf("-f raw file containing RRC configuration (generated by gNB)\n");
|
|
printf("-g Channel model: [A] TDLA30, [B] TDLB100, [C] TDLC300, e.g. -g A\n");
|
|
printf("-h This message\n");
|
|
printf("-H Slot number\n");
|
|
printf("-i Change channel estimation technique. Arguments list: Frequency domain {0:Linear interpolation, 1:PRB based averaging}, Time domain {0:Estimates of last DMRS symbol, 1:Average of DMRS symbols}\n");
|
|
printf("-m Numerology\n");
|
|
printf("-n Number of frames to simulate\n");
|
|
printf("-o Introduce delay in terms of number of samples\n");
|
|
printf("-p Precoding matrix index\n");
|
|
printf("-q MCS Table index\n");
|
|
printf("-s Starting SNR, runs from SNR0 to SNR0 + 5 dB. If n_frames is 1 then just SNR is simulated\n");
|
|
printf("-S Ending SNR, runs from SNR0 to SNR1\n");
|
|
printf("-t Acceptable effective throughput (in percentage)\n");
|
|
printf("-v Maximum number of rounds\n");
|
|
printf("-w Write txdata to binary file (one frame)\n");
|
|
printf("-x Num of layer for PDSCH\n");
|
|
printf("-y Number of TX antennas used in gNB\n");
|
|
printf("-z Number of RX antennas used in UE\n");
|
|
printf("-F Input filename (.txt format) for RX conformance testing\n");
|
|
printf("-I Maximum LDPC decoder iterations\n");
|
|
printf("-L <log level, 0(errors), 1(warning), 2(analysis), 3(info), 4(debug), 5(trace)>\n");
|
|
printf("-P Print DLSCH performances\n");
|
|
printf("-R N_RB_DL\n");
|
|
printf("-T Enable PTRS, arguments list L_PTRS{0,1,2} K_PTRS{2,4}, e.g. -T 2 0 2 \n");
|
|
printf("-U Change DMRS Config, arguments list DMRS TYPE{0=A,1=B} DMRS AddPos{0:2} DMRS ConfType{1:2}, e.g. -U 3 0 2 1 \n");
|
|
printf("-X gNB thread pool configuration, n => no threads\n");
|
|
printf("-Z Output filename (.csv format) for stats\n");
|
|
exit (-1);
|
|
break;
|
|
}
|
|
}
|
|
printf("%d\n", slot);
|
|
logInit();
|
|
set_glog(loglvl);
|
|
/* initialize the sin table */
|
|
InitSinLUT();
|
|
|
|
get_softmodem_params()->phy_test = 1;
|
|
get_softmodem_params()->usim_test = 1;
|
|
get_softmodem_params()->do_ra = 0;
|
|
IS_SOFTMODEM_DLSIM = true;
|
|
|
|
if (snr1set==0)
|
|
snr1 = snr0+10;
|
|
|
|
RC.gNB = (PHY_VARS_gNB**) malloc(sizeof(PHY_VARS_gNB *));
|
|
RC.gNB[0] = (PHY_VARS_gNB*) malloc(sizeof(PHY_VARS_gNB ));
|
|
memset(RC.gNB[0],0,sizeof(PHY_VARS_gNB));
|
|
|
|
gNB = RC.gNB[0];
|
|
gNB->ofdm_offset_divisor = UINT_MAX;
|
|
gNB->phase_comp = true; // we need to perform phase compensation, otherwise everything will fail
|
|
frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH)
|
|
frame_parms->nb_antennas_tx = n_tx;
|
|
frame_parms->nb_antennas_rx = n_rx;
|
|
frame_parms->N_RB_DL = N_RB_DL;
|
|
frame_parms->N_RB_UL = N_RB_DL;
|
|
|
|
AssertFatal((gNB->if_inst = NR_IF_Module_init(0)) != NULL, "Cannot register interface");
|
|
gNB->if_inst->NR_PHY_config_req = nr_phy_config_request;
|
|
|
|
NR_ServingCellConfigCommon_t *scc = calloc(1,sizeof(*scc));;
|
|
prepare_scc(scc);
|
|
uint64_t ssb_bitmap = 1; // Enable only first SSB with index ssb_indx=0
|
|
fill_scc_sim(scc, &ssb_bitmap, N_RB_DL, N_RB_DL, mu, mu);
|
|
fix_scc(scc, ssb_bitmap);
|
|
|
|
frame_structure_t frame_structure = {0};
|
|
frame_type_t frame_type = TDD;
|
|
config_frame_structure(mu,
|
|
scc->tdd_UL_DL_ConfigurationCommon,
|
|
get_tdd_period_idx(scc->tdd_UL_DL_ConfigurationCommon),
|
|
frame_type,
|
|
&frame_structure);
|
|
AssertFatal(is_dl_slot(slot, &frame_structure), "The slot selected is not DL. Can't run DLSIM\n");
|
|
|
|
// TODO do a UECAP for phy-sim
|
|
nr_pdsch_AntennaPorts_t pdsch_AntennaPorts = {0};
|
|
pdsch_AntennaPorts.N1 = n_tx > 1 ? n_tx >> 1 : 1;
|
|
pdsch_AntennaPorts.N2 = 1;
|
|
pdsch_AntennaPorts.XP = n_tx > 1 ? 2 : 1;
|
|
const nr_mac_config_t conf = {.pdsch_AntennaPorts = pdsch_AntennaPorts,
|
|
.pusch_AntennaPorts = n_tx,
|
|
.minRXTXTIME = 6,
|
|
.do_CSIRS = 0,
|
|
.do_SRS = 0,
|
|
.maxMIMO_layers = g_nrOfLayers,
|
|
.force_256qam_off = false,
|
|
.timer_config.sr_ProhibitTimer = 0,
|
|
.timer_config.sr_TransMax = 64,
|
|
.timer_config.sr_ProhibitTimer_v1700 = 0,
|
|
.timer_config.t300 = 400,
|
|
.timer_config.t301 = 400,
|
|
.timer_config.t310 = 2000,
|
|
.timer_config.n310 = 10,
|
|
.timer_config.t311 = 3000,
|
|
.timer_config.n311 = 1,
|
|
.timer_config.t319 = 400,
|
|
.num_agg_level_candidates = {0, 0, 1, 1, 0}};
|
|
const nr_rlc_configuration_t rlc_config = {
|
|
.srb = {
|
|
.t_poll_retransmit = 45,
|
|
.t_reassembly = 35,
|
|
.t_status_prohibit = 0,
|
|
.poll_pdu = -1,
|
|
.poll_byte = -1,
|
|
.max_retx_threshold = 8,
|
|
.sn_field_length = 12,
|
|
},
|
|
.drb_am = {
|
|
.t_poll_retransmit = 45,
|
|
.t_reassembly = 15,
|
|
.t_status_prohibit = 15,
|
|
.poll_pdu = 64,
|
|
.poll_byte = 1024 * 500,
|
|
.max_retx_threshold = 32,
|
|
.sn_field_length = 18,
|
|
},
|
|
.drb_um = {
|
|
.t_reassembly = 15,
|
|
.sn_field_length = 12,
|
|
}
|
|
};
|
|
|
|
RC.nb_nr_macrlc_inst = 1;
|
|
RC.nb_nr_mac_CC = (int*)malloc(RC.nb_nr_macrlc_inst*sizeof(int));
|
|
for (i = 0; i < RC.nb_nr_macrlc_inst; i++)
|
|
RC.nb_nr_mac_CC[i] = 1;
|
|
mac_top_init_gNB(ngran_gNB, scc, NULL, &conf, &rlc_config);
|
|
gNB_mac = RC.nrmac[0];
|
|
nr_mac_config_scc(RC.nrmac[0], scc, &conf);
|
|
|
|
gNB_mac->dl_bler.harq_round_max = num_rounds;
|
|
|
|
/*
|
|
// read in SCGroupConfig
|
|
AssertFatal(scg_fd != NULL,"no reconfig.raw file\n");
|
|
char buffer[1024];
|
|
int msg_len=fread(buffer,1,1024,scg_fd);
|
|
NR_RRCReconfiguration_t *NR_RRCReconfiguration = NULL;
|
|
|
|
printf("Decoding NR_RRCReconfiguration (%d bytes)\n",msg_len);
|
|
asn_dec_rval_t dec_rval = uper_decode_complete( NULL,
|
|
&asn_DEF_NR_RRCReconfiguration,
|
|
(void **)&NR_RRCReconfiguration,
|
|
(uint8_t *)buffer,
|
|
msg_len);
|
|
|
|
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
|
|
AssertFatal(1==0,"NR_RRCReConfiguration decode error\n");
|
|
// free the memory
|
|
SEQUENCE_free( &asn_DEF_NR_RRCReconfiguration, NR_RRCReconfiguration, 1 );
|
|
exit(-1);
|
|
}
|
|
fclose(scg_fd);
|
|
|
|
AssertFatal(NR_RRCReconfiguration->criticalExtensions.present == NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration,"wrong NR_RRCReconfiguration->criticalExstions.present type\n");
|
|
|
|
NR_RRCReconfiguration_IEs_t *reconfig_ies = NR_RRCReconfiguration->criticalExtensions.choice.rrcReconfiguration;
|
|
NR_CellGroupConfig_t *secondaryCellGroup = NULL;
|
|
dec_rval = uper_decode_complete( NULL,
|
|
&asn_DEF_NR_CellGroupConfig,
|
|
(void **)&secondaryCellGroup,
|
|
(uint8_t *)reconfig_ies->secondaryCellGroup->buf,
|
|
reconfig_ies->secondaryCellGroup->size);
|
|
|
|
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
|
|
AssertFatal(1==0,"NR_CellGroupConfig decode error\n");
|
|
// free the memory
|
|
SEQUENCE_free( &asn_DEF_NR_CellGroupConfig, secondaryCellGroup, 1 );
|
|
exit(-1);
|
|
}
|
|
|
|
NR_ServingCellConfigCommon_t *scc = secondaryCellGroup->spCellConfig->reconfigurationWithSync->spCellConfigCommon;
|
|
*/
|
|
|
|
NR_ServingCellConfig_t *scd = calloc(1,sizeof(*scd));
|
|
prepare_scd(scd);
|
|
/* removes unnecessary BWPs, if any */
|
|
fix_scd(scd);
|
|
|
|
gNB->ap_N1 = pdsch_AntennaPorts.N1;
|
|
gNB->ap_N2 = pdsch_AntennaPorts.N2;
|
|
gNB->ap_XP = pdsch_AntennaPorts.XP;
|
|
|
|
validate_input_pmi(&gNB_mac->config[0], pdsch_AntennaPorts, g_nrOfLayers, g_pmi);
|
|
|
|
NR_UE_NR_Capability_t *UE_Capability_nr = CALLOC(1,sizeof(NR_UE_NR_Capability_t));
|
|
prepare_sim_uecap(UE_Capability_nr, scc, mu, N_RB_DL, g_mcsTableIdx, 0);
|
|
rnti_t rnti = 0x1234;
|
|
int uid = 0;
|
|
NR_CellGroupConfig_t *secondaryCellGroup = get_default_secondaryCellGroup(scc, scd, UE_Capability_nr, 0, 1, &conf, uid);
|
|
secondaryCellGroup->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(rnti, uid, scc);
|
|
|
|
/* -U option modify DMRS */
|
|
if(modify_dmrs) {
|
|
update_dmrs_config(secondaryCellGroup, dmrs_arg);
|
|
}
|
|
/* -T option enable PTRS */
|
|
if(enable_ptrs) {
|
|
update_ptrs_config(secondaryCellGroup, &rbSize, &mcsIndex, ptrs_arg);
|
|
}
|
|
|
|
|
|
//xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup);
|
|
|
|
// UE dedicated configuration
|
|
nr_mac_add_test_ue(RC.nrmac[0], rnti, secondaryCellGroup);
|
|
// reset preprocessor to the one of DLSIM after it has been set during
|
|
// nr_mac_config_scc()
|
|
gNB_mac->pre_processor_dl = nr_dlsim_preprocessor;
|
|
phy_init_nr_gNB(gNB);
|
|
N_RB_DL = gNB->frame_parms.N_RB_DL;
|
|
NR_UE_info_t *UE_info = RC.nrmac[0]->UE_info.connected_ue_list[0];
|
|
|
|
configure_UE_BWP(RC.nrmac[0], scc, UE_info, false, NR_SearchSpace__searchSpaceType_PR_ue_Specific, -1, -1);
|
|
|
|
// stub to configure frame_parms
|
|
// nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions);
|
|
// call MAC to configure common parameters
|
|
|
|
/* nr_mac_add_test_ue() has created one user, so set the scheduling
|
|
* parameters from command line in global variables that will be picked up by
|
|
* scheduling preprocessor */
|
|
if (g_mcsIndex < 0) g_mcsIndex = 9;
|
|
if (g_rbStart < 0) g_rbStart=0;
|
|
if (g_rbSize < 0) g_rbSize = N_RB_DL - g_rbStart;
|
|
|
|
double fs,txbw,rxbw;
|
|
uint32_t samples;
|
|
|
|
get_samplerate_and_bw(mu,
|
|
N_RB_DL,
|
|
frame_parms->threequarter_fs,
|
|
&fs,
|
|
&samples,
|
|
&txbw,
|
|
&rxbw);
|
|
|
|
gNB2UE = new_channel_desc_scm(n_tx,
|
|
n_rx,
|
|
channel_model,
|
|
fs/1e6,//sampling frequency in MHz
|
|
0,
|
|
txbw,
|
|
DS_TDL,
|
|
0.0,
|
|
CORR_LEVEL_LOW,
|
|
0,
|
|
delay,
|
|
0,
|
|
0);
|
|
|
|
if (gNB2UE==NULL) {
|
|
printf("Problem generating channel model. Exiting.\n");
|
|
exit(-1);
|
|
}
|
|
|
|
frame_length_complex_samples = frame_parms->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
|
|
//frame_length_complex_samples_no_prefix = frame_parms->samples_per_subframe_wCP*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
|
|
int slot_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0);
|
|
int slot_length = slot_offset - frame_parms->get_samples_slot_timestamp(slot-1,frame_parms,0);
|
|
|
|
s_re = malloc(n_tx*sizeof(double*));
|
|
s_im = malloc(n_tx*sizeof(double*));
|
|
r_re = malloc(n_rx*sizeof(double*));
|
|
r_im = malloc(n_rx*sizeof(double*));
|
|
txdata = malloc(n_tx*sizeof(int*));
|
|
|
|
for (i = 0; i < n_tx; i++) {
|
|
s_re[i] = calloc(1, slot_length * sizeof(double));
|
|
s_im[i] = calloc(1, slot_length * sizeof(double));
|
|
|
|
printf("Allocating %d samples for txdata\n", frame_length_complex_samples);
|
|
txdata[i] = calloc(1, frame_length_complex_samples * sizeof(int));
|
|
}
|
|
|
|
for (i = 0; i < n_rx; i++) {
|
|
r_re[i] = calloc(1, slot_length * sizeof(double));
|
|
r_im[i] = calloc(1, slot_length * sizeof(double));
|
|
}
|
|
|
|
if (pbch_file_fd!=NULL) {
|
|
load_pbch_desc(pbch_file_fd);
|
|
}
|
|
|
|
|
|
//configure UE
|
|
UE = malloc(sizeof(PHY_VARS_NR_UE));
|
|
memset((void*)UE,0,sizeof(PHY_VARS_NR_UE));
|
|
PHY_vars_UE_g = malloc(sizeof(PHY_VARS_NR_UE**));
|
|
PHY_vars_UE_g[0] = malloc(sizeof(PHY_VARS_NR_UE*));
|
|
PHY_vars_UE_g[0][0] = UE;
|
|
memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS));
|
|
UE->frame_parms.nb_antennas_rx = n_rx;
|
|
UE->frame_parms.nb_antenna_ports_gNB = n_tx;
|
|
UE->nrLDPC_coding_interface = gNB->nrLDPC_coding_interface;
|
|
UE->max_ldpc_iterations = max_ldpc_iterations;
|
|
init_nr_ue_phy_cpu_stats(&UE->phy_cpu_stats);
|
|
UE->is_synchronized = 1;
|
|
|
|
if (init_nr_ue_signal(UE, 1) != 0)
|
|
{
|
|
printf("Error at UE NR initialisation\n");
|
|
exit(-1);
|
|
}
|
|
|
|
init_nr_ue_transport(UE);
|
|
|
|
nr_l2_init_ue(1);
|
|
UE_mac = get_mac_inst(0);
|
|
ue_init_config_request(UE_mac, get_slots_per_frame_from_scs(mu));
|
|
|
|
UE->if_inst = nr_ue_if_module_init(0);
|
|
UE->if_inst->scheduled_response = nr_ue_scheduled_response;
|
|
UE->if_inst->phy_config_request = nr_ue_phy_config_request;
|
|
UE->if_inst->dl_indication = nr_ue_dl_indication;
|
|
UE->if_inst->ul_indication = dummy_nr_ue_ul_indication;
|
|
UE->chest_freq = chest_type[0];
|
|
UE->chest_time = chest_type[1];
|
|
|
|
UE_mac->if_module = nr_ue_if_module_init(0);
|
|
|
|
unsigned int available_bits=0;
|
|
unsigned char *estimated_output_bit=NULL;
|
|
unsigned char *test_input_bit=NULL;
|
|
unsigned int errors_bit = 0;
|
|
|
|
initFloatingCoresTpool(dlsch_threads, &nrUE_params.Tpool, false, "UE-tpool");
|
|
|
|
// generate signal
|
|
AssertFatal(input_fd==NULL,"Not ready for input signal file\n");
|
|
|
|
// clone CellGroup to have a separate copy at UE
|
|
NR_CellGroupConfig_t *UE_CellGroup = clone_CellGroupConfig(secondaryCellGroup);
|
|
|
|
//Configure UE
|
|
NR_BCCH_BCH_Message_t *mib = get_new_MIB_NR(scc);
|
|
nr_rrc_mac_config_req_mib(0, 0, mib->message.choice.mib, false);
|
|
nr_rrc_mac_config_req_cg(0, 0, UE_CellGroup, UE_Capability_nr);
|
|
|
|
asn1cFreeStruc(asn_DEF_NR_CellGroupConfig, UE_CellGroup);
|
|
|
|
UE_mac->state = UE_CONNECTED;
|
|
UE_mac->ra.ra_state = nrRA_SUCCEEDED;
|
|
|
|
nr_phy_data_t phy_data = {0};
|
|
fapi_nr_dl_config_request_t dl_config = {.sfn = frame, .slot = slot};
|
|
nr_scheduled_response_t scheduled_response = {.dl_config = &dl_config, .phy_data = &phy_data, .mac = UE_mac};
|
|
|
|
nr_ue_phy_config_request(&UE_mac->phy_config);
|
|
//NR_COMMON_channels_t *cc = RC.nrmac[0]->common_channels;
|
|
int ret = 1;
|
|
initNamedTpool(gNBthreads, &gNB->threadPool, true, "gNB-tpool");
|
|
initNotifiedFIFO(&gNB->L1_tx_free);
|
|
initNotifiedFIFO(&gNB->L1_tx_filled);
|
|
initNotifiedFIFO(&gNB->L1_tx_out);
|
|
// we create 2 threads for L1 tx processing
|
|
notifiedFIFO_elt_t *msgL1Tx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t),0,&gNB->L1_tx_free,processSlotTX);
|
|
processingData_L1tx_t *msgDataTx = (processingData_L1tx_t *)NotifiedFifoData(msgL1Tx);
|
|
init_DLSCH_struct(gNB, msgDataTx);
|
|
msgDataTx->slot = slot;
|
|
msgDataTx->frame = frame;
|
|
memset(msgDataTx->ssb, 0, 64*sizeof(NR_gNB_SSB_t));
|
|
gNB->msgDataTx = msgDataTx;
|
|
|
|
// Buffers to store internal memory of slot process
|
|
int rx_size = (((14 * UE->frame_parms.N_RB_DL * 12 * sizeof(int32_t)) + 15) >> 4) << 4;
|
|
UE->phy_sim_rxdataF = calloc(sizeof(int32_t *) * UE->frame_parms.nb_antennas_rx * g_nrOfLayers,
|
|
UE->frame_parms.samples_per_slot_wCP * sizeof(int32_t));
|
|
UE->phy_sim_pdsch_llr = calloc(1, (8 * (3 * 8 * 8448)) * sizeof(int16_t)); // Max length
|
|
UE->phy_sim_pdsch_rxdataF_ext = calloc(sizeof(int32_t *) * UE->frame_parms.nb_antennas_rx * g_nrOfLayers, rx_size);
|
|
UE->phy_sim_pdsch_rxdataF_comp = calloc(sizeof(int32_t *) * UE->frame_parms.nb_antennas_rx * g_nrOfLayers, rx_size);
|
|
UE->phy_sim_pdsch_dl_ch_estimates = calloc(sizeof(int32_t *) * UE->frame_parms.nb_antennas_rx * g_nrOfLayers, rx_size);
|
|
UE->phy_sim_pdsch_dl_ch_estimates_ext = calloc(sizeof(int32_t *) * UE->frame_parms.nb_antennas_rx * g_nrOfLayers, rx_size);
|
|
int a_segments = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*NR_MAX_NB_LAYERS; //number of segments to be allocated
|
|
if (g_rbSize != 273) {
|
|
a_segments = a_segments*g_rbSize;
|
|
a_segments = (a_segments/273)+1;
|
|
}
|
|
uint32_t dlsch_bytes = a_segments*1056; // allocated bytes per segment
|
|
UE->phy_sim_dlsch_b = calloc(1, dlsch_bytes);
|
|
|
|
// csv file
|
|
if (filename_csv != NULL) {
|
|
csv_file = fopen(filename_csv, "a");
|
|
if (csv_file == NULL) {
|
|
printf("Can't open file \"%s\", errno %d\n", filename_csv, errno);
|
|
free(s_re);
|
|
free(s_im);
|
|
free(r_re);
|
|
free(r_im);
|
|
free(txdata);
|
|
return 1;
|
|
}
|
|
// adding name of parameters into file
|
|
fprintf(csv_file,"SNR,false_positive,");
|
|
for (int r = 0; r < num_rounds; r++)
|
|
fprintf(csv_file,"n_errors_%d,errors_scrambling_%d,channel_bler_%d,channel_ber_%d,",r,r,r,r);
|
|
fprintf(csv_file,"avg_round,eff_rate,eff_throughput,TBS\n");
|
|
}
|
|
//---------------
|
|
|
|
Sched_INFO = malloc(sizeof(*Sched_INFO));
|
|
if (Sched_INFO == NULL) {
|
|
LOG_E(PHY, "out of memory\n");
|
|
exit(1);
|
|
}
|
|
|
|
for (SNR = snr0; SNR < snr1 && !stop; SNR += .2) {
|
|
|
|
varArray_t *table_tx=initVarArray(1000,sizeof(double));
|
|
reset_meas(&gNB->phy_proc_tx);
|
|
reset_meas(&gNB->dlsch_scrambling_stats);
|
|
reset_meas(&gNB->dlsch_interleaving_stats);
|
|
reset_meas(&gNB->dlsch_rate_matching_stats);
|
|
reset_meas(&gNB->dlsch_segmentation_stats);
|
|
reset_meas(&gNB->dlsch_modulation_stats);
|
|
reset_meas(&gNB->dlsch_encoding_stats);
|
|
reset_meas(&gNB->dci_generation_stats);
|
|
reset_meas(&gNB->tinput);
|
|
reset_meas(&gNB->tprep);
|
|
reset_meas(&gNB->tparity);
|
|
reset_meas(&gNB->toutput);
|
|
reset_meas(&gNB->phase_comp_stats);
|
|
|
|
uint32_t errors_scrambling[16] = {0};
|
|
int n_errors[16] = {0};
|
|
int round_trials[16] = {0};
|
|
double roundStats = {0};
|
|
double blerStats[16] = {0};
|
|
double berStats[16] = {0};
|
|
|
|
effRate = 0;
|
|
//n_errors2 = 0;
|
|
//n_alamouti = 0;
|
|
n_false_positive = 0;
|
|
if (n_trials== 1) num_rounds = 1;
|
|
|
|
NR_gNB_DLSCH_t *gNB_dlsch = &msgDataTx->dlsch[0][0];
|
|
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &gNB_dlsch->harq_process.pdsch_pdu.pdsch_pdu_rel15;
|
|
|
|
for (trial = 0; trial < n_trials && !stop; trial++) {
|
|
|
|
errors_bit = 0;
|
|
//multipath channel
|
|
//multipath_channel(gNB2UE,s_re,s_im,r_re,r_im,frame_length_complex_samples,0);
|
|
|
|
UE_proc.frame_rx = frame;
|
|
UE_proc.nr_slot_rx = slot;
|
|
UE_proc.gNB_id = 0;
|
|
|
|
NR_UE_DLSCH_t *dlsch0 = &phy_data.dlsch[0];
|
|
|
|
int harq_pid = slot;
|
|
NR_DL_UE_HARQ_t *UE_harq_process = &UE->dl_harq_processes[0][harq_pid];
|
|
|
|
UE_harq_process->decodeResult = false;
|
|
round = 0;
|
|
UE_harq_process->DLround = round;
|
|
UE_harq_process->first_rx = 1;
|
|
|
|
memset(Sched_INFO, 0, sizeof(*Sched_INFO));
|
|
Sched_INFO->sched_response_id = -1;
|
|
|
|
while (round < num_rounds && !UE_harq_process->decodeResult && !stop) {
|
|
round_trials[round]++;
|
|
|
|
clear_nr_nfapi_information(RC.nrmac[0], 0, frame, slot, &Sched_INFO->DL_req, &Sched_INFO->TX_req, &Sched_INFO->UL_dci_req);
|
|
UE_info->UE_sched_ctrl.harq_processes[harq_pid].ndi = !(trial&1);
|
|
UE_info->UE_sched_ctrl.harq_processes[harq_pid].round = round;
|
|
|
|
// nr_schedule_ue_spec() requires the mutex to be locked
|
|
NR_SCHED_LOCK(&gNB_mac->sched_lock);
|
|
nr_schedule_ue_spec(0, frame, slot, &Sched_INFO->DL_req, &Sched_INFO->TX_req);
|
|
NR_SCHED_UNLOCK(&gNB_mac->sched_lock);
|
|
Sched_INFO->module_id = 0;
|
|
Sched_INFO->CC_id = 0;
|
|
Sched_INFO->frame = frame;
|
|
Sched_INFO->slot = slot;
|
|
Sched_INFO->UL_dci_req.numPdus = 0;
|
|
pushNotifiedFIFO(&gNB->L1_tx_free,msgL1Tx);
|
|
nr_schedule_response(Sched_INFO);
|
|
|
|
/* PTRS values for DLSIM calculations */
|
|
nfapi_nr_dl_tti_request_body_t *dl_req = &Sched_INFO->DL_req.dl_tti_request_body;
|
|
nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[1];
|
|
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15;
|
|
pdu_bit_map = pdsch_pdu_rel15->pduBitmap;
|
|
if(pdu_bit_map & 0x1) {
|
|
set_ptrs_symb_idx(&dlPtrsSymPos,
|
|
pdsch_pdu_rel15->NrOfSymbols,
|
|
pdsch_pdu_rel15->StartSymbolIndex,
|
|
1<<pdsch_pdu_rel15->PTRSTimeDensity,
|
|
pdsch_pdu_rel15->dlDmrsSymbPos);
|
|
ptrsSymbPerSlot = get_ptrs_symbols_in_slot(dlPtrsSymPos, pdsch_pdu_rel15->StartSymbolIndex, pdsch_pdu_rel15->NrOfSymbols);
|
|
ptrsRePerSymb = ((rel15->rbSize + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity);
|
|
LOG_D(PHY,"[DLSIM] PTRS Symbols in a slot: %2u, RE per Symbol: %3u, RE in a slot %4d\n", ptrsSymbPerSlot, ptrsRePerSymb, ptrsSymbPerSlot * ptrsRePerSymb);
|
|
}
|
|
|
|
msgDataTx->ssb[0].ssb_pdu.ssb_pdu_rel15.bchPayload=0x001234;
|
|
msgDataTx->ssb[0].ssb_pdu.ssb_pdu_rel15.SsbBlockIndex = 0;
|
|
msgDataTx->gNB = gNB;
|
|
|
|
start_meas(&gNB->phy_proc_tx);
|
|
phy_procedures_gNB_TX(msgDataTx,frame,slot,1);
|
|
stop_meas(&gNB->phy_proc_tx);
|
|
|
|
int txdataF_offset = slot * frame_parms->samples_per_slot_wCP;
|
|
|
|
if (n_trials==1) {
|
|
LOG_M("txsigF0.m","txsF0=",
|
|
&gNB->common_vars.txdataF[0][0][txdataF_offset +2 * frame_parms->ofdm_symbol_size],
|
|
frame_parms->ofdm_symbol_size,
|
|
1,
|
|
1);
|
|
if (gNB->frame_parms.nb_antennas_tx>1)
|
|
LOG_M("txsigF1.m","txsF1=",
|
|
&gNB->common_vars.txdataF[0][1][txdataF_offset + 2 * frame_parms->ofdm_symbol_size],
|
|
frame_parms->ofdm_symbol_size,
|
|
1,
|
|
1);
|
|
}
|
|
if (n_trials == 1)
|
|
printf("slot_offset %d, txdataF_offset %d \n", slot_offset, txdataF_offset);
|
|
|
|
//TODO: loop over slots
|
|
for (aa=0; aa<gNB->frame_parms.nb_antennas_tx; aa++) {
|
|
|
|
if (cyclic_prefix_type == 1) {
|
|
PHY_ofdm_mod((int *)&gNB->common_vars.txdataF[0][aa][txdataF_offset],
|
|
(int *)&txdata[aa][slot_offset],
|
|
frame_parms->ofdm_symbol_size,
|
|
12,
|
|
frame_parms->nb_prefix_samples,
|
|
CYCLIC_PREFIX);
|
|
} else {
|
|
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT];
|
|
for (int i = 0; i < 14; i++) {
|
|
was_symbol_used[i] = true;
|
|
}
|
|
nr_normal_prefix_mod(&gNB->common_vars.txdataF[0][aa][txdataF_offset],
|
|
&txdata[aa][slot_offset],
|
|
14,
|
|
frame_parms,
|
|
slot,
|
|
was_symbol_used);
|
|
}
|
|
}
|
|
if (n_trials==1) {
|
|
char filename[100];//LOG_M
|
|
for (aa=0;aa<n_tx;aa++) {
|
|
sprintf(filename,"txsig%d.m", aa);//LOG_M
|
|
LOG_M(filename,"txs", &txdata[aa][slot_offset +frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples0],6*(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples),1,1);
|
|
}
|
|
if (output_fd) {
|
|
printf("writing txdata to binary file\n");
|
|
fwrite(txdata[0], sizeof(int32_t), frame_length_complex_samples, output_fd);
|
|
}
|
|
}
|
|
|
|
int txlev[n_tx];
|
|
int txlev_sum = 0;
|
|
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);
|
|
}
|
|
|
|
for (i = 0; i < slot_length; i++) {
|
|
for (aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
|
|
s_re[aa][i] = ((double)(((short *)&txdata[aa][slot_offset]))[(i << 1)]);
|
|
s_im[aa][i] = ((double)(((short *)&txdata[aa][slot_offset]))[(i << 1) + 1]);
|
|
}
|
|
}
|
|
|
|
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*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*rel15->rbSize));
|
|
|
|
for (aa = 0; aa < n_rx; aa++) {
|
|
bzero(r_re[aa], slot_length * sizeof(double));
|
|
bzero(r_im[aa], slot_length * sizeof(double));
|
|
}
|
|
|
|
// Apply MIMO Channel
|
|
multipath_channel(gNB2UE, s_re, s_im, r_re, r_im, slot_length, 0, (n_trials == 1) ? 1 : 0);
|
|
add_noise(UE->common_vars.rxdata,
|
|
(const double **)r_re,
|
|
(const double **)r_im,
|
|
sigma2,
|
|
slot_length,
|
|
slot_offset,
|
|
ts,
|
|
delay,
|
|
pdu_bit_map,
|
|
0x1,
|
|
UE->frame_parms.nb_antennas_rx);
|
|
dl_config.sfn = frame;
|
|
dl_config.slot = slot;
|
|
ue_dci_configuration(UE_mac, &dl_config, frame, slot);
|
|
nr_ue_scheduled_response(&scheduled_response);
|
|
|
|
pbch_pdcch_processing(UE,
|
|
&UE_proc,
|
|
&phy_data);
|
|
pdsch_processing(UE,
|
|
&UE_proc,
|
|
&phy_data);
|
|
//----------------------------------------------------------
|
|
//---------------------- count errors ----------------------
|
|
//----------------------------------------------------------
|
|
|
|
if (dlsch0->last_iteration_cnt >= dlsch0->max_ldpc_iterations)
|
|
n_errors[round]++;
|
|
|
|
int16_t *UE_llr = (int16_t*)UE->phy_sim_pdsch_llr;
|
|
|
|
TBS = dlsch0->dlsch_config.TBS;//rel15->TBSize[0];
|
|
uint16_t length_dmrs = get_num_dmrs(rel15->dlDmrsSymbPos);
|
|
uint16_t nb_rb = rel15->rbSize;
|
|
uint8_t nb_re_dmrs = rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6*dlsch0->dlsch_config.n_dmrs_cdm_groups : 4*dlsch0->dlsch_config.n_dmrs_cdm_groups;
|
|
uint8_t mod_order = rel15->qamModOrder[0];
|
|
uint8_t nb_symb_sch = rel15->NrOfSymbols;
|
|
uint32_t unav_res = ptrsSymbPerSlot * ptrsRePerSymb;
|
|
available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, unav_res, mod_order, rel15->nrOfLayers);
|
|
if (pdu_bit_map & 0x1) {
|
|
if (trial == 0 && round == 0) {
|
|
printf("[DLSIM][PTRS] Available bits are: %5u, removed PTRS bits are: %5u \n", available_bits, (ptrsSymbPerSlot * ptrsRePerSymb * rel15->nrOfLayers * mod_order));
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < available_bits; i++) {
|
|
if(((gNB_dlsch->harq_process.f[i] == 0) && (UE_llr[i] <= 0)) ||
|
|
((gNB_dlsch->harq_process.f[i] == 1) && (UE_llr[i] >= 0)))
|
|
{
|
|
if (errors_scrambling[round] == 0) {
|
|
LOG_D(PHY,"First bit in error in unscrambling = %d\n",i);
|
|
}
|
|
errors_scrambling[round]++;
|
|
}
|
|
}
|
|
|
|
//printf("dlsim round %d ends\n",round);
|
|
round++;
|
|
} // round
|
|
|
|
if (test_input_bit == NULL) {
|
|
test_input_bit = (unsigned char *)malloc16(sizeof(unsigned char) * TBS);
|
|
estimated_output_bit = (unsigned char *)malloc16(sizeof(unsigned char) * TBS);
|
|
}
|
|
for (i = 0; i < TBS; i++) {
|
|
|
|
estimated_output_bit[i] = (UE->phy_sim_dlsch_b[i/8] & (1 << (i & 7))) >> (i & 7);
|
|
test_input_bit[i] = (gNB_dlsch->harq_process.b[i / 8] & (1 << (i & 7))) >> (i & 7); // Further correct for multiple segments
|
|
|
|
if (estimated_output_bit[i] != test_input_bit[i]) {
|
|
if(errors_bit == 0)
|
|
LOG_D(PHY,"First bit in error in decoding = %d\n",i);
|
|
errors_bit++;
|
|
}
|
|
|
|
}
|
|
////////////////////////////////////////////////////////////
|
|
|
|
if (errors_bit > 0) {
|
|
n_false_positive++;
|
|
if (n_trials == 1)
|
|
printf("errors_bit = %u (trial %d)\n", errors_bit, trial);
|
|
}
|
|
roundStats += ((float)round);
|
|
if (UE_harq_process->decodeResult)
|
|
effRate += ((float)TBS) / round;
|
|
} // noise trials
|
|
|
|
roundStats /= ((float)n_trials);
|
|
|
|
for (int r = 0; r < num_rounds; r++) {
|
|
blerStats[r] = (double)n_errors[r] / round_trials[r];
|
|
berStats[r] = (double)errors_scrambling[r] / available_bits / round_trials[r];
|
|
}
|
|
|
|
effRate /= n_trials;
|
|
printf("*****************************************\n");
|
|
printf("SNR %f: n_errors (%d/%d", SNR, n_errors[0], round_trials[0]);
|
|
for (int r = 1; r < num_rounds; r++)
|
|
printf(",%d/%d", n_errors[r], round_trials[r]);
|
|
printf(") (negative CRC), false_positive %d/%d, errors_scrambling (%u/%u", n_false_positive, n_trials, errors_scrambling[0], available_bits * round_trials[0]);
|
|
for (int r = 1; r < num_rounds; r++)
|
|
printf(",%u/%u", errors_scrambling[r], available_bits * round_trials[r]);
|
|
printf(")\n\n");
|
|
dump_pdsch_stats(stdout,gNB);
|
|
printf("SNR %f: Channel BLER (%e", SNR, blerStats[0]);
|
|
for (int r = 1; r < num_rounds; r++)
|
|
printf(",%e", blerStats[r]);
|
|
printf("), Channel BER (%e", berStats[0]);
|
|
for (int r = 1; r < num_rounds; r++)
|
|
printf(",%e", berStats[r]);
|
|
printf(") Avg round %.2f, Eff Rate %.4f bits/slot, Eff Throughput %.2f, TBS %u bits/slot\n", roundStats, effRate, effRate / TBS * 100, TBS);
|
|
printf("*****************************************\n");
|
|
printf("\n");
|
|
// writing to csv file
|
|
if (filename_csv != NULL) { // means we are asked to print stats to CSV
|
|
fprintf(csv_file,"%f,%d/%d,",SNR,n_false_positive,n_trials);
|
|
for (int r = 0; r < num_rounds; r++)
|
|
fprintf(csv_file,"%d/%d,%u/%u,%f,%e,",n_errors[r], round_trials[r], errors_scrambling[r], available_bits * round_trials[r],blerStats[r],berStats[r]);
|
|
fprintf(csv_file,"%.2f,%.4f,%.2f,%u\n", roundStats, effRate, effRate / TBS * 100, TBS);
|
|
}
|
|
if (print_perf==1) {
|
|
printf("\ngNB TX function statistics (per %d us slot, NPRB %d, mcs %d, C %d, block %d)\n",
|
|
1000 >> *scc->ssbSubcarrierSpacing,
|
|
g_rbSize,
|
|
g_mcsIndex,
|
|
UE->dl_harq_processes[0][slot].C,
|
|
msgDataTx->dlsch[0][0].harq_process.pdsch_pdu.pdsch_pdu_rel15.TBSize[0] << 3);
|
|
printDistribution(&gNB->phy_proc_tx,table_tx,"PHY proc tx");
|
|
printStatIndent2(&gNB->dci_generation_stats, "DCI encoding time");
|
|
printStatIndent2(&gNB->dlsch_encoding_stats,"DLSCH encoding time");
|
|
printStatIndent3(&gNB->dlsch_segmentation_stats,"DLSCH segmentation time");
|
|
printStatIndent3(&gNB->tinput,"DLSCH LDPC input processing time");
|
|
printStatIndent3(&gNB->tprep,"DLSCH LDPC input preparation time");
|
|
printStatIndent3(&gNB->tparity,"DLSCH LDPC parity generation time");
|
|
printStatIndent3(&gNB->toutput,"DLSCH LDPC output generation time");
|
|
printStatIndent3(&gNB->dlsch_rate_matching_stats,"DLSCH Rate Mataching time");
|
|
printStatIndent3(&gNB->dlsch_interleaving_stats, "DLSCH Interleaving time");
|
|
printStatIndent2(&gNB->dlsch_modulation_stats,"DLSCH modulation time");
|
|
printStatIndent2(&gNB->dlsch_scrambling_stats, "DLSCH scrambling time");
|
|
printStatIndent2(&gNB->dlsch_precoding_stats,"DLSCH Mapping/Precoding time");
|
|
if (gNB->phase_comp)
|
|
printStatIndent2(&gNB->phase_comp_stats, "Phase Compensation");
|
|
|
|
printf("\nUE function statistics (per %d us slot)\n", 1000 >> *scc->ssbSubcarrierSpacing);
|
|
for (int i = RX_PDSCH_STATS; i <= DLSCH_PROCEDURES_STATS; i++) {
|
|
printStatIndent(&UE->phy_cpu_stats.cpu_time_stats[i], UE->phy_cpu_stats.cpu_time_stats[i].meas_name);
|
|
}
|
|
}
|
|
|
|
if (n_trials == 1) {
|
|
unsigned int op_format = 1;
|
|
unsigned int dec = 1;
|
|
if (output_fd) { // Write in bin format
|
|
op_format |= MATLAB_RAW;
|
|
}
|
|
|
|
LOG_M("rxsig0.m", "rxs0", UE->common_vars.rxdata[0], frame_length_complex_samples, dec, op_format);
|
|
if (UE->frame_parms.nb_antennas_rx>1)
|
|
LOG_M("rxsig1.m", "rxs1", UE->common_vars.rxdata[1], frame_length_complex_samples, dec, op_format);
|
|
LOG_M("rxF0.m", "rxF0", UE->phy_sim_rxdataF, frame_parms->samples_per_slot_wCP, dec, op_format);
|
|
LOG_M("rxF_ext.m", "rxFe", UE->phy_sim_pdsch_rxdataF_ext, g_rbSize * 12 * 14, dec, op_format);
|
|
const uint32_t numReSym = (g_rbSize * 12 + 15) & (~15);
|
|
const uint32_t numValidReSym = g_rbSize * 12;
|
|
{
|
|
const int s = rel15->StartSymbolIndex;
|
|
const int n = rel15->NrOfSymbols;
|
|
for (int i = s; i < s + n; i++) {
|
|
char fName[50];
|
|
snprintf(fName, sizeof(fName), "chestF0_ext_s%d.m", i);
|
|
LOG_M(fName,
|
|
"chF0_ext",
|
|
((c16_t *)UE->phy_sim_pdsch_dl_ch_estimates_ext) + (i * numReSym),
|
|
numValidReSym,
|
|
dec,
|
|
op_format);
|
|
snprintf(fName, sizeof(fName), "rxF_comp_s%d.m", i);
|
|
LOG_M(fName, "rxFc", ((c16_t *)UE->phy_sim_pdsch_rxdataF_comp) + (i * numReSym), numValidReSym, dec, op_format);
|
|
}
|
|
}
|
|
LOG_M("chestF0.m", "chF0", UE->phy_sim_pdsch_dl_ch_estimates, frame_parms->ofdm_symbol_size * 14, dec, op_format);
|
|
op_format = (op_format & (~1));
|
|
LOG_M("rxF_llr.m", "rxFllr", UE->phy_sim_pdsch_llr, available_bits, dec, op_format);
|
|
break;
|
|
}
|
|
|
|
if (effRate > (eff_tp_check*TBS)) {
|
|
printf("PDSCH test OK\n");
|
|
ret = 0;
|
|
break;
|
|
}
|
|
|
|
} // NSR
|
|
|
|
free(Sched_INFO);
|
|
|
|
free_channel_desc_scm(gNB2UE);
|
|
|
|
for (i = 0; i < n_tx; i++) {
|
|
free(s_re[i]);
|
|
free(s_im[i]);
|
|
free(txdata[i]);
|
|
}
|
|
for (i = 0; i < n_rx; i++) {
|
|
free(r_re[i]);
|
|
free(r_im[i]);
|
|
}
|
|
|
|
free(s_re);
|
|
free(s_im);
|
|
free(r_re);
|
|
free(r_im);
|
|
free(txdata);
|
|
free(test_input_bit);
|
|
free(estimated_output_bit);
|
|
free(UE->phy_sim_rxdataF);
|
|
free(UE->phy_sim_pdsch_llr);
|
|
free(UE->phy_sim_pdsch_rxdataF_ext);
|
|
free(UE->phy_sim_pdsch_rxdataF_comp);
|
|
free(UE->phy_sim_pdsch_dl_ch_estimates);
|
|
free(UE->phy_sim_pdsch_dl_ch_estimates_ext);
|
|
free(UE->phy_sim_dlsch_b);
|
|
|
|
free_nrLDPC_coding_interface(&gNB->nrLDPC_coding_interface);
|
|
|
|
if (output_fd)
|
|
fclose(output_fd);
|
|
|
|
if (input_fd)
|
|
fclose(input_fd);
|
|
|
|
if (scg_fd)
|
|
fclose(scg_fd);
|
|
|
|
// closing csv file
|
|
if (filename_csv != NULL) { // means we are asked to print stats to CSV
|
|
fclose(csv_file);
|
|
free(filename_csv);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
void update_ptrs_config(NR_CellGroupConfig_t *secondaryCellGroup, uint16_t *rbSize, uint8_t *mcsIndex, int8_t *ptrs_arg)
|
|
{
|
|
NR_BWP_Downlink_t *bwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[0];
|
|
long ptrsFreqDenst[] = {25, 115};
|
|
long ptrsTimeDenst[] = {2, 4, 10};
|
|
|
|
long epre_Ratio = 0;
|
|
long reOffset = 0;
|
|
|
|
if(ptrs_arg[0] ==0) {
|
|
ptrsTimeDenst[2]= *mcsIndex -1;
|
|
}
|
|
else if(ptrs_arg[0] == 1) {
|
|
ptrsTimeDenst[1]= *mcsIndex - 1;
|
|
ptrsTimeDenst[2]= *mcsIndex + 1;
|
|
}
|
|
else if(ptrs_arg[0] ==2) {
|
|
ptrsTimeDenst[0]= *mcsIndex - 1;
|
|
ptrsTimeDenst[1]= *mcsIndex + 1;
|
|
}
|
|
else {
|
|
printf("[DLSIM] Wrong L_PTRS value, using default values 1\n");
|
|
}
|
|
/* L = 4 if Imcs < MCS4 */
|
|
if(ptrs_arg[1] ==2) {
|
|
ptrsFreqDenst[0]= *rbSize - 1;
|
|
ptrsFreqDenst[1]= *rbSize + 1;
|
|
}
|
|
else if(ptrs_arg[1] == 4) {
|
|
ptrsFreqDenst[1]= *rbSize - 1;
|
|
}
|
|
else {
|
|
printf("[DLSIM] Wrong K_PTRS value, using default values 2\n");
|
|
}
|
|
printf("[DLSIM] PTRS Enabled with L %d, K %d \n", 1<<ptrs_arg[0], ptrs_arg[1] );
|
|
/* overwrite the values */
|
|
rrc_config_dl_ptrs_params(bwp, ptrsFreqDenst, ptrsTimeDenst, &epre_Ratio, &reOffset);
|
|
}
|
|
|
|
void update_dmrs_config(NR_CellGroupConfig_t *scg, int8_t* dmrs_arg)
|
|
{
|
|
int8_t mapping_type = typeA;//default value
|
|
int8_t add_pos = pdsch_dmrs_pos0;//default value
|
|
int8_t dmrs_config_type = NFAPI_NR_DMRS_TYPE1;//default value
|
|
|
|
if(dmrs_arg[0] == 0) {
|
|
mapping_type = typeA;
|
|
}
|
|
else if (dmrs_arg[0] == 1) {
|
|
mapping_type = typeB;
|
|
} else {
|
|
AssertFatal(1==0,"Incorrect Mappingtype, valid options 0-typeA, 1-typeB\n");
|
|
}
|
|
|
|
/* Additional DMRS positions 0 ,1 ,2 and 3 */
|
|
if (dmrs_arg[1] >= 0 && dmrs_arg[1] < 4) {
|
|
add_pos = dmrs_arg[1];
|
|
} else {
|
|
AssertFatal(1==0,"Incorrect Additional Position, valid options 0-pos1, 1-pos1, 2-pos2, 3-pos3\n");
|
|
}
|
|
|
|
/* DMRS Conf Type 1 or 2 */
|
|
if(dmrs_arg[2] == 1) {
|
|
dmrs_config_type = NFAPI_NR_DMRS_TYPE1;
|
|
} else if(dmrs_arg[2] == 2) {
|
|
dmrs_config_type = NFAPI_NR_DMRS_TYPE2;
|
|
}
|
|
|
|
NR_BWP_Downlink_t *bwp = scg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[0];
|
|
|
|
AssertFatal((bwp->bwp_Dedicated->pdsch_Config != NULL && bwp->bwp_Dedicated->pdsch_Config->choice.setup != NULL), "Base RRC reconfig structures are not allocated.\n");
|
|
|
|
if(mapping_type == typeA) {
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA = calloc(1,sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA));
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->present= NR_SetupRelease_DMRS_DownlinkConfig_PR_setup;
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup = calloc(1,sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup));
|
|
if (dmrs_config_type == NFAPI_NR_DMRS_TYPE2)
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type = calloc(1,sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type));
|
|
else
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type = NULL;
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->maxLength=NULL;
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->scramblingID0=NULL;
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->scramblingID1=NULL;
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS=NULL;
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NULL;
|
|
printf("DLSIM: Allocated Mapping TypeA in RRC reconfig message\n");
|
|
}
|
|
|
|
if(mapping_type == typeB) {
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeB = calloc(1,sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeB));
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeB->present= NR_SetupRelease_DMRS_DownlinkConfig_PR_setup;
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup = calloc(1,sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup));
|
|
if (dmrs_config_type == NFAPI_NR_DMRS_TYPE2)
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->dmrs_Type = calloc(1,sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->dmrs_Type));
|
|
else
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->dmrs_Type = NULL;
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->maxLength=NULL;
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->scramblingID0=NULL;
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->scramblingID1=NULL;
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->phaseTrackingRS=NULL;
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->dmrs_AdditionalPosition = NULL;
|
|
printf("DLSIM: Allocated Mapping TypeB in RRC reconfig message\n");
|
|
}
|
|
|
|
struct NR_SetupRelease_DMRS_DownlinkConfig *dmrs_MappingtypeA = bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA;
|
|
struct NR_SetupRelease_DMRS_DownlinkConfig *dmrs_MappingtypeB = bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeB;
|
|
|
|
|
|
NR_DMRS_DownlinkConfig_t *dmrs_config = (mapping_type == typeA) ? dmrs_MappingtypeA->choice.setup : dmrs_MappingtypeB->choice.setup;
|
|
|
|
if (add_pos != 2) { // pos0,pos1,pos3
|
|
if (dmrs_config->dmrs_AdditionalPosition == NULL) {
|
|
dmrs_config->dmrs_AdditionalPosition = calloc(1,sizeof(*dmrs_MappingtypeA->choice.setup->dmrs_AdditionalPosition));
|
|
}
|
|
switch (add_pos) {
|
|
case 0:
|
|
*dmrs_config->dmrs_AdditionalPosition = NR_DMRS_DownlinkConfig__dmrs_AdditionalPosition_pos0;
|
|
break;
|
|
case 1:
|
|
*dmrs_config->dmrs_AdditionalPosition = NR_DMRS_DownlinkConfig__dmrs_AdditionalPosition_pos1;
|
|
break;
|
|
case 3:
|
|
*dmrs_config->dmrs_AdditionalPosition = NR_DMRS_DownlinkConfig__dmrs_AdditionalPosition_pos3;
|
|
break;
|
|
default:
|
|
AssertFatal(false, "DMRS additional position %d not valid\n", add_pos);
|
|
}
|
|
} else { // if NULL, Value pos2
|
|
free(dmrs_config->dmrs_AdditionalPosition);
|
|
dmrs_config->dmrs_AdditionalPosition = NULL;
|
|
}
|
|
|
|
for (int i=0;i<bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.count;i++) {
|
|
bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[i]->mappingType = mapping_type;
|
|
}
|
|
|
|
printf("[DLSIM] DMRS Config is modified with Mapping Type %d, Additional Positions %d Config. Type %d \n", mapping_type, add_pos, dmrs_config_type);
|
|
}
|