Commit f9bff3d6 authored by Robert Schmidt's avatar Robert Schmidt

Merge branch 'integration_2024_w51' into 'develop'

Integration: `2024.w51`

Closes #879

See merge request oai/openairinterface5g!3180

* !3155 UL BLER vs SNR plot
* !3170 Replace AssertFatal with static_assert for cmdline arguments check
* !3172 A script to run CI tests locally.
* !3151 Optimize PHY_ofdm_mod CYCLIC_PREFIX in case of incidentally aligned pointers
* !3164 Fix and refactor channel average
* !3154 Fix TPMI for UL retransmissions
parents 5bd2eb86 a82b1450
......@@ -47,6 +47,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,CONTAINERS,HELP,SCA,PHYSIM,CLUSTER):
py_param_file_present = False
py_params={}
force_local = False
while len(argvs) > 1:
myArgv = argvs.pop(1) # 0th is this file's name
......@@ -54,6 +55,9 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,CONTAINERS,HELP,SCA,PHYSIM,CLUSTER):
if re.match('^\-\-help$', myArgv, re.IGNORECASE):
HELP.GenericHelp(CONST.Version)
sys.exit(0)
if re.match('^\-\-local$', myArgv, re.IGNORECASE):
force_local = True
#--apply=<filename> as parameters file, to replace inline parameters
elif re.match('^\-\-Apply=(.+)$', myArgv, re.IGNORECASE):
......@@ -271,4 +275,4 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,CONTAINERS,HELP,SCA,PHYSIM,CLUSTER):
HELP.GenericHelp(CONST.Version)
sys.exit('Invalid Parameter: ' + myArgv)
return py_param_file_present, py_params, mode
return py_param_file_present, py_params, mode, force_local
......@@ -217,6 +217,8 @@ class RemoteCmd(Cmd):
return client
def _lookup_ssh_config(hostname):
if is_local(hostname):
raise ValueError("Using localhost as SSH target is not allowed: use LocalCmd instead.")
ssh_config = paramiko.SSHConfig()
user_config_file = os.path.expanduser("~/.ssh/config")
if os.path.exists(user_config_file):
......
......@@ -43,6 +43,8 @@ def GenericHelp(vers):
print(' InitiateHtml, FinalizeHtml')
print(' TerminateeNB, TerminateHSS, TerminateMME, TerminateSPGW')
print(' LogCollectBuild, LogCollecteNB, LogCollectHSS, LogCollectMME, LogCollectSPGW, LogCollectPing, LogCollectIperf')
print(' --local Force local execution: rewrites the test xml script before running to always execute on localhost. Assumes')
print(' images are available locally, will not remove any images and will run inside the current repo directory')
def GitSrvHelp(repository,branch,commit,mergeallow,targetbranch):
print(' --ranRepository=[OAI RAN Repository URL] -- ' + repository)
......
......@@ -212,13 +212,17 @@ def ExecuteActionWithParam(action):
elif action == 'Initialize_UE' or action == 'Attach_UE' or action == 'Detach_UE' or action == 'Terminate_UE' or action == 'CheckStatusUE' or action == 'DataEnable_UE' or action == 'DataDisable_UE':
CiTestObj.ue_ids = test.findtext('id').split(' ')
if test.findtext('nodes'):
CiTestObj.nodes = test.findtext('nodes').split(' ')
if len(CiTestObj.ue_ids) != len(CiTestObj.nodes):
logging.error('Number of Nodes are not equal to the total number of UEs')
sys.exit("Mismatch in number of Nodes and UIs")
if force_local:
# Change all execution targets to localhost
CiTestObj.nodes = ['localhost'] * len(CiTestObj.ue_ids)
else:
CiTestObj.nodes = [None] * len(CiTestObj.ue_ids)
if test.findtext('nodes'):
CiTestObj.nodes = test.findtext('nodes').split(' ')
if len(CiTestObj.ue_ids) != len(CiTestObj.nodes):
logging.error('Number of Nodes are not equal to the total number of UEs')
sys.exit("Mismatch in number of Nodes and UIs")
else:
CiTestObj.nodes = [None] * len(CiTestObj.ue_ids)
if action == 'Initialize_UE':
success = CiTestObj.InitializeUE(HTML)
elif action == 'Attach_UE':
......@@ -238,13 +242,17 @@ def ExecuteActionWithParam(action):
CiTestObj.ping_args = test.findtext('ping_args')
CiTestObj.ping_packetloss_threshold = test.findtext('ping_packetloss_threshold')
CiTestObj.ue_ids = test.findtext('id').split(' ')
if test.findtext('nodes'):
CiTestObj.nodes = test.findtext('nodes').split(' ')
if len(CiTestObj.ue_ids) != len(CiTestObj.nodes):
logging.error('Number of Nodes are not equal to the total number of UEs')
sys.exit("Mismatch in number of Nodes and UIs")
if force_local:
# Change all execution targets to localhost
CiTestObj.nodes = ['localhost'] * len(CiTestObj.ue_ids)
else:
CiTestObj.nodes = [None] * len(CiTestObj.ue_ids)
if test.findtext('nodes'):
CiTestObj.nodes = test.findtext('nodes').split(' ')
if len(CiTestObj.ue_ids) != len(CiTestObj.nodes):
logging.error('Number of Nodes are not equal to the total number of UEs')
sys.exit("Mismatch in number of Nodes and UIs")
else:
CiTestObj.nodes = [None] * len(CiTestObj.ue_ids)
ping_rttavg_threshold = test.findtext('ping_rttavg_threshold') or ''
success = CiTestObj.Ping(HTML,EPC,CONTAINERS)
......@@ -252,15 +260,19 @@ def ExecuteActionWithParam(action):
CiTestObj.iperf_args = test.findtext('iperf_args')
CiTestObj.ue_ids = test.findtext('id').split(' ')
CiTestObj.svr_id = test.findtext('svr_id') or None
if test.findtext('nodes'):
CiTestObj.nodes = test.findtext('nodes').split(' ')
if len(CiTestObj.ue_ids) != len(CiTestObj.nodes):
logging.error('Number of Nodes are not equal to the total number of UEs')
sys.exit("Mismatch in number of Nodes and UIs")
if force_local:
# Change all execution targets to localhost
CiTestObj.nodes = ['localhost'] * len(CiTestObj.ue_ids)
else:
CiTestObj.nodes = [None] * len(CiTestObj.ue_ids)
if test.findtext('nodes'):
CiTestObj.nodes = test.findtext('nodes').split(' ')
if len(CiTestObj.ue_ids) != len(CiTestObj.nodes):
logging.error('Number of Nodes are not equal to the total number of UEs')
sys.exit("Mismatch in number of Nodes and UIs")
else:
CiTestObj.nodes = [None] * len(CiTestObj.ue_ids)
if test.findtext('svr_node'):
CiTestObj.svr_node = test.findtext('svr_node')
CiTestObj.svr_node = test.findtext('svr_node') if not force_local else 'localhost'
CiTestObj.iperf_packetloss_threshold = test.findtext('iperf_packetloss_threshold')
CiTestObj.iperf_bitrate_threshold = test.findtext('iperf_bitrate_threshold') or '90'
CiTestObj.iperf_profile = test.findtext('iperf_profile') or 'balanced'
......@@ -356,6 +368,9 @@ def ExecuteActionWithParam(action):
elif action == 'Undeploy_Object':
success = CONTAINERS.UndeployObject(HTML, RAN)
elif action == 'Create_Workspace':
if force_local:
# Do not create a working directory when running locally. Current repo directory will be used
return True
success = CONTAINERS.Create_Workspace(HTML)
elif action == 'Run_Physim':
......@@ -375,6 +390,9 @@ def ExecuteActionWithParam(action):
success = CONTAINERS.Push_Image_to_Local_Registry(HTML, svr_id)
elif action == 'Pull_Local_Registry' or action == 'Clean_Test_Server_Images':
if force_local:
# Do not pull or remove images when running locally. User is supposed to handle image creation & cleanup
return True
svr_id = test.findtext('svr_id')
images = test.findtext('images').split()
# hack: for FlexRIC, we need to overwrite the tag to use
......@@ -463,7 +481,9 @@ CLUSTER = cls_cluster.Cluster()
#-----------------------------------------------------------
import args_parse
py_param_file_present, py_params, mode = args_parse.ArgsParse(sys.argv,CiTestObj,RAN,HTML,EPC,CONTAINERS,HELP,SCA,PHYSIM,CLUSTER)
# Force local execution, move all execution targets to localhost
force_local = False
py_param_file_present, py_params, mode, force_local = args_parse.ArgsParse(sys.argv,CiTestObj,RAN,HTML,EPC,CONTAINERS,HELP,SCA,PHYSIM,CLUSTER)
......
#!/bin/bash
set -e
SHORT_COMMIT_SHA=$(git rev-parse --short=8 HEAD)
COMMIT_SHA=$(git rev-parse HEAD)
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
REPO_PATH=$(dirname $(realpath $0))/../
TESTCASE=$1
if [ $# -eq 0 ]
then
echo "Provide a testcase as an argument"
exit 1
fi
# The script assumes you've build the following images:
#
# docker build . -f docker/Dockerfile.gNB.ubuntu22 -t oai-gnb
# docker build . -f docker/Dockerfile.nrUE.ubuntu22 -t oai-nr-ue
#
# The images above depend on the following images:
#
# docker build . -f docker/Dockerfile.build.ubuntu22 -t ran-build
# dokcer build . -f docker/Dockerfile.base.ubuntu22 -t ran-base
docker tag oai-nr-ue oai-ci/oai-nr-ue:develop-${SHORT_COMMIT_SHA}
docker tag oai-gnb oai-ci/oai-gnb:develop-${SHORT_COMMIT_SHA}
python3 main.py --mode=TesteNB --ranRepository=NONE --ranBranch=${CURRENT_BRANCH} \
--ranCommitID=${COMMIT_SHA} --ranAllowMerge=false \
--ranTargetBranch=NONE --eNBIPAddress=NONE --eNBUserName=NONE --eNBPassword=NONE \
--eNBSourceCodePath=NONE --EPCIPAddress=NONE --EPCType=OAI --eNBPassword=NONE \
--eNBSourceCodePath=${REPO_PATH} --EPCIPAddress=NONE \
--EPCUserName=NONE --EPCPassword=NONE --EPCSourceCodePath=NONE \
--XMLTestFile=xml_files/${TESTCASE} --local
......@@ -3,7 +3,7 @@ add_subdirectory(config/yaml)
configure_file(oai_version.h.in oai_version.h @ONLY)
add_library(instrumentation INTERFACE instrumentation.h)
add_library(instrumentation INTERFACE)
target_include_directories(instrumentation INTERFACE .)
if (TRACY_ENABLE)
target_link_libraries(instrumentation INTERFACE Tracy::TracyClient)
......
......@@ -105,8 +105,9 @@ void get_common_options(configmodule_interface_t *cfg, uint32_t execmask)
paramdef_t cmdline_params[] = CMDLINE_PARAMS_DESC;
checkedparam_t cmdline_CheckParams[] = CMDLINE_PARAMS_CHECK_DESC;
static_assert(sizeofArray(cmdline_params) == sizeofArray(cmdline_CheckParams),
"cmdline_params and cmdline_CheckParams should have the same size");
int numparams = sizeofArray(cmdline_params);
AssertFatal(numparams == sizeofArray(cmdline_CheckParams), "Error in arrays size (%d!=%lu)\n", numparams, sizeofArray(cmdline_CheckParams));
config_set_checkfunctions(cmdline_params, cmdline_CheckParams, numparams);
config_get(cfg, cmdline_params, numparams, NULL);
nfapi_index = config_paramidx_fromname(cmdline_params, numparams, "nfapi");
......@@ -115,9 +116,10 @@ void get_common_options(configmodule_interface_t *cfg, uint32_t execmask)
paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ;
checkedparam_t cmdline_log_CheckParams[] = CMDLINE_LOGPARAMS_CHECK_DESC;
int numlogparams = sizeofArray(cmdline_logparams);
AssertFatal(numlogparams == sizeofArray(cmdline_log_CheckParams), "Error in arrays size (%d!=%lu)\n", numlogparams, sizeofArray(cmdline_log_CheckParams));
static_assert(sizeofArray(cmdline_logparams) == sizeofArray(cmdline_log_CheckParams),
"cmdline_logparams and cmdline_log_CheckParams should have the same size");
int numlogparams = sizeofArray(cmdline_logparams);
config_set_checkfunctions(cmdline_logparams, cmdline_log_CheckParams, numlogparams);
config_get(cfg, cmdline_logparams, numlogparams, NULL);
......
......@@ -38,7 +38,7 @@
@param nb_prefix_samples The number of prefix/suffix/zero samples
@param etype Type of extension (CYCLIC_PREFIX,CYCLIC_SUFFIX,ZEROS)
*/
void PHY_ofdm_mod(int *input,
void PHY_ofdm_mod(const int *input,
int *output,
int fftsize,
unsigned char nb_symbols,
......
......@@ -40,6 +40,9 @@ This section deals with basic functions for OFDM Modulation.
#include "PHY/LTE_TRANSPORT/transport_common_proto.h"
//#define DEBUG_OFDM_MOD
// Use 64-byte alignment for IDFT output buffer to ensure no
// runtime error in case IDFT implementation uses AVX-512.
#define IDFT_OUTPUT_BUFFER_ALIGNMENT 64
void normal_prefix_mod(int32_t *txdataF,int32_t *txdata,uint8_t nsymb,LTE_DL_FRAME_PARMS *frame_parms)
{
......@@ -122,109 +125,90 @@ void nr_normal_prefix_mod(c16_t *txdataF, c16_t *txdata, uint8_t nsymb, const NR
}
void PHY_ofdm_mod(int *input, /// pointer to complex input
int *output, /// pointer to complex output
int fftsize, /// FFT_SIZE
unsigned char nb_symbols, /// number of OFDM symbols
unsigned short nb_prefix_samples, /// cyclic prefix length
Extension_t etype /// type of extension
)
void PHY_ofdm_mod(const int *input, /// pointer to complex input
int *output, /// pointer to complex output
int fftsize, /// FFT_SIZE
unsigned char nb_symbols, /// number of OFDM symbols
unsigned short nb_prefix_samples, /// cyclic prefix length
Extension_t etype /// type of extension
)
{
if (nb_symbols == 0)
return;
if(nb_symbols == 0) return;
int16_t temp[2*2*6144*4] __attribute__((aligned(32)));
int i,j;
volatile int *output_ptr=(int*)0;
int *temp_ptr=(int*)0;
idft_size_idx_t idft_size = get_idft(fftsize);
#ifdef DEBUG_OFDM_MOD
printf("[PHY] OFDM mod (size %d,prefix %d) Symbols %d, input %p, output %p\n",
fftsize,nb_prefix_samples,nb_symbols,input,output);
fftsize,
nb_prefix_samples,
nb_symbols,
input,
output);
#endif
for (i=0; i<nb_symbols; i++) {
for (int i = 0; i < nb_symbols; i++) {
#ifdef DEBUG_OFDM_MOD
printf("[PHY] symbol %d/%d offset %d (%p,%p -> %p)\n",i,nb_symbols,i*fftsize+(i*nb_prefix_samples),input,&input[i*fftsize],&output[(i*fftsize) + ((i)*nb_prefix_samples)]);
printf("[PHY] symbol %d/%d offset %d (%p,%p -> %p)\n",
i,
nb_symbols,
i * fftsize + (i * nb_prefix_samples),
input,
&input[i * fftsize],
&output[(i * fftsize) + ((i)*nb_prefix_samples)]);
#endif
// on AVX2 need 256-bit alignment
idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)temp, 1);
// Copy to frame buffer with Cyclic Extension
// Note: will have to adjust for synchronization offset!
switch (etype) {
case CYCLIC_PREFIX:
output_ptr = &output[(i*fftsize) + ((1+i)*nb_prefix_samples)];
temp_ptr = (int *)temp;
// msg("Doing cyclic prefix method\n");
{
memcpy((void*)output_ptr,(void*)temp_ptr,fftsize<<2);
case CYCLIC_PREFIX: {
int *output_ptr = &output[(i * fftsize) + ((1 + i) * nb_prefix_samples)];
// Current idft implementation uses AVX-256: Check if buffer is already aligned to 256 bits (32 bytes)
if ((uintptr_t)output_ptr % 32 == 0) {
// output ptr is aligned, do ifft inplace
idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)output_ptr, 1);
} else {
// output ptr is not aligned, needs an extra memcpy
c16_t temp[fftsize] __attribute__((aligned(IDFT_OUTPUT_BUFFER_ALIGNMENT)));
idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)temp, 1);
memcpy((void *)output_ptr, (void *)temp, sizeof(temp));
}
// perform cyclic prefix insertion
memcpy((void *)&output_ptr[-nb_prefix_samples], (void *)&output_ptr[fftsize - nb_prefix_samples], nb_prefix_samples * sizeof(c16_t));
break;
}
memcpy((void*)&output_ptr[-nb_prefix_samples],(void*)&output_ptr[fftsize-nb_prefix_samples],nb_prefix_samples<<2);
break;
case CYCLIC_SUFFIX:
output_ptr = &output[(i*fftsize)+ (i*nb_prefix_samples)];
temp_ptr = (int *)temp;
// msg("Doing cyclic suffix method\n");
for (j=0; j<fftsize ; j++) {
output_ptr[j] = temp_ptr[2*j];
case CYCLIC_SUFFIX: {
// Use alignment of 64 bytes
c16_t temp[fftsize] __attribute__((aligned(IDFT_OUTPUT_BUFFER_ALIGNMENT)));
idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)temp, 1);
int *output_ptr = &output[(i * fftsize) + (i * nb_prefix_samples)];
memcpy(output_ptr, temp, sizeof(temp));
memcpy(&output_ptr[fftsize], temp, nb_prefix_samples * sizeof(c16_t));
break;
}
case ZEROS:
for (j=0; j<nb_prefix_samples; j++)
output_ptr[fftsize+j] = output_ptr[j];
break;
case ZEROS:
break;
case NONE:
// msg("NO EXTENSION!\n");
output_ptr = &output[fftsize];
temp_ptr = (int *)temp;
for (j=0; j<fftsize ; j++) {
output_ptr[j] = temp_ptr[2*j];
break;
case NONE: {
c16_t temp[fftsize] __attribute__((aligned(IDFT_OUTPUT_BUFFER_ALIGNMENT)));
idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)temp, 1);
int *output_ptr = &output[i * fftsize];
memcpy(output_ptr, temp, sizeof(temp));
break;
}
break;
default:
break;
default:
break;
}
}
}
void do_OFDM_mod(c16_t **txdataF, c16_t **txdata, uint32_t frame,uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms)
{
......
......@@ -209,25 +209,17 @@ static void nr_ulsch_channel_level(int size_est,
uint32_t len,
uint8_t nrOfLayers)
{
simde__m128i *ul_ch128, avg128U;
int16_t x = factor2(len);
int16_t y = (len)>>x;
for (int aatx = 0; aatx < nrOfLayers; aatx++) {
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
//clear average level
avg128U = simde_mm_setzero_si128();
ul_ch128 = (simde__m128i *)&ul_ch_estimates_ext[aatx * frame_parms->nb_antennas_rx + aarx][symbol * len];
for (int i = 0; i < len >> 2; i++) {
avg128U = simde_mm_add_epi32(avg128U, simde_mm_srai_epi32(simde_mm_madd_epi16(ul_ch128[i], ul_ch128[i]), x));
}
simde__m128i *ul_ch128 = (simde__m128i *)&ul_ch_estimates_ext[aatx * frame_parms->nb_antennas_rx + aarx][symbol * len];
int32_t *avg32i = (int32_t *)&avg128U;
int64_t avg64 = (int64_t)avg32i[0] + avg32i[1] + avg32i[2] + avg32i[3];
avg[aatx * frame_parms->nb_antennas_rx + aarx] = avg64 / y;
//compute average level
avg[aatx * frame_parms->nb_antennas_rx + aarx] = simde_mm_average(ul_ch128, len, x, y);
//LOG_D(PHY, "Channel level: %d\n", avg[aatx * frame_parms->nb_antennas_rx + aarx]);
}
}
......
......@@ -226,30 +226,12 @@ void nr_pdcch_channel_level(int32_t rx_size,
int nb_rb)
{
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
//clear average level
simde__m128i avg128P = simde_mm_setzero_si128();
simde__m128i *dl_ch128 = (simde__m128i *)&dl_ch_estimates_ext[aarx][symbol * nb_rb * 12];
for (int rb = 0; rb < (nb_rb * 3) >> 2; rb++) {
avg128P = simde_mm_add_epi32(avg128P,simde_mm_madd_epi16(dl_ch128[0],dl_ch128[0]));
avg128P = simde_mm_add_epi32(avg128P,simde_mm_madd_epi16(dl_ch128[1],dl_ch128[1]));
avg128P = simde_mm_add_epi32(avg128P,simde_mm_madd_epi16(dl_ch128[2],dl_ch128[2]));
// for (int i=0;i<24;i+=2) printf("pdcch channel re %d (%d,%d)\n",(rb*12)+(i>>1),((int16_t*)dl_ch128)[i],((int16_t*)dl_ch128)[i+1]);
dl_ch128+=3;
/*
if (rb==0) {
print_shorts("dl_ch128",&dl_ch128[0]);
print_shorts("dl_ch128",&dl_ch128[1]);
print_shorts("dl_ch128",&dl_ch128[2]);
}
*/
}
simde__m128i *dl_ch128 = (simde__m128i *)&dl_ch_estimates_ext[aarx][symbol * nb_rb * 12];
DevAssert(nb_rb);
avg[aarx] = 0;
for (int i = 0; i < 4; i++)
avg[aarx] += ((int32_t *)&avg128P)[i] / (nb_rb * 9);
LOG_DDD("Channel level : %d\n",avg[aarx]);
//compute average level
avg[aarx] = simde_mm_average(dl_ch128, nb_rb * 12, 0, nb_rb * 12);
//LOG_DDD("Channel level : %d\n", avg[aarx]);
}
}
......
......@@ -1098,28 +1098,20 @@ void nr_dlsch_channel_level(uint32_t rx_size_symbol,
int32_t avg[MAX_ANT][MAX_ANT],
uint32_t len)
{
simde__m128i *dl_ch128, avg128D;
//nb_rb*nre = y * 2^x
int16_t x = factor2(len);
int16_t y = (len) >> x;
uint32_t nb_rb_0 = len / NR_NB_SC_PER_RB + ((len % NR_NB_SC_PER_RB) ? 1 : 0);
LOG_D(NR_PHY, "nb_rb_0 %d len %d = %d * 2^(%d)\n", nb_rb_0, len, y, x);
for (int aatx = 0; aatx < n_tx; aatx++) {
for (int aarx = 0; aarx < n_rx; aarx++) {
//clear average level
avg128D = simde_mm_setzero_si128();
dl_ch128 = (simde__m128i *)dl_ch_estimates_ext[(aatx * n_rx) + aarx];
simde__m128i *dl_ch128 = (simde__m128i *)dl_ch_estimates_ext[(aatx * n_rx) + aarx];
for (int rb = 0; rb < nb_rb_0; rb++) {
avg128D = simde_mm_add_epi32(avg128D,simde_mm_srai_epi32(simde_mm_madd_epi16(dl_ch128[0],dl_ch128[0]),x));
avg128D = simde_mm_add_epi32(avg128D,simde_mm_srai_epi32(simde_mm_madd_epi16(dl_ch128[1],dl_ch128[1]),x));
avg128D = simde_mm_add_epi32(avg128D,simde_mm_srai_epi32(simde_mm_madd_epi16(dl_ch128[2],dl_ch128[2]),x));
dl_ch128+=3;
}
int32_t *tmp = (int32_t *)&avg128D;
avg[aatx][aarx] = ((int64_t)tmp[0] + tmp[1] + tmp[2] + tmp[3]) / y;
LOG_D(PHY, "Channel level: %d\n", avg[aatx][aarx]);
//compute average level
avg[aatx][aarx] = simde_mm_average(dl_ch128, nb_rb_0 * 12, x, y);
//LOG_D(PHY, "Channel level: %d\n", avg[aatx][aarx]);
}
}
}
......
......@@ -208,31 +208,14 @@ int nr_pbch_channel_level(struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER
const NR_DL_FRAME_PARMS *frame_parms,
int nb_re)
{
int16_t nb_rb=nb_re/12;
simde__m128i avg128;
simde__m128i *dl_ch128;
int avg1=0,avg2=0;
int32_t avg2 = 0;
for (int aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
//clear average level
avg128 = simde_mm_setzero_si128();
dl_ch128=(simde__m128i *)dl_ch_estimates_ext[aarx];
for (int rb=0; rb<nb_rb; rb++) {
avg128 = simde_mm_add_epi32(avg128, simde_mm_madd_epi16(dl_ch128[0],dl_ch128[0]));
avg128 = simde_mm_add_epi32(avg128, simde_mm_madd_epi16(dl_ch128[1],dl_ch128[1]));
avg128 = simde_mm_add_epi32(avg128, simde_mm_madd_epi16(dl_ch128[2],dl_ch128[2]));
dl_ch128+=3;
/*
if (rb==0) {
print_shorts("dl_ch128",&dl_ch128[0]);
print_shorts("dl_ch128",&dl_ch128[1]);
print_shorts("dl_ch128",&dl_ch128[2]);
}*/
}
for (int i = 0; i < 4; i++)
avg1 += ((int *)&avg128)[i] / (nb_rb * 12);
simde__m128i *dl_ch128 = (simde__m128i *)dl_ch_estimates_ext[aarx];
//compute average level
int32_t avg1 = simde_mm_average(dl_ch128, nb_re, 0, nb_re);
if (avg1>avg2)
avg2 = avg1;
......
......@@ -49,13 +49,6 @@
#define SSE_INTRIN_H
#include <simde/x86/mmx.h>
#include <simde/x86/sse.h>
#include <simde/x86/sse2.h>
#include <simde/x86/sse3.h>
#include <simde/x86/ssse3.h>
#include <simde/x86/sse4.1.h>
#include <simde/x86/sse4.2.h>
#include <simde/x86/avx2.h>
#include <simde/x86/fma.h>
#if defined(__x86_64) || defined(__i386__)
......@@ -81,31 +74,101 @@
* OAI specific
*/
static const short minusConjug128[8]__attribute__((aligned(16))) = {-1,1,-1,1,-1,1,-1,1};
static inline simde__m128i mulByConjugate128(simde__m128i *a, simde__m128i *b, int8_t output_shift) {
simde__m128i realPart = simde_mm_madd_epi16(*a,*b);
realPart = simde_mm_srai_epi32(realPart,output_shift);
simde__m128i imagPart = simde_mm_shufflelo_epi16(*b, SIMDE_MM_SHUFFLE(2,3,0,1));
imagPart = simde_mm_shufflehi_epi16(imagPart, SIMDE_MM_SHUFFLE(2,3,0,1));
imagPart = simde_mm_sign_epi16(imagPart,*(simde__m128i *)minusConjug128);
imagPart = simde_mm_madd_epi16(imagPart,*a);
imagPart = simde_mm_srai_epi32(imagPart,output_shift);
simde__m128i lowPart = simde_mm_unpacklo_epi32(realPart,imagPart);
simde__m128i highPart = simde_mm_unpackhi_epi32(realPart,imagPart);
return ( simde_mm_packs_epi32(lowPart,highPart));
static const short minusConjug128[8] __attribute__((aligned(16))) = {-1, 1, -1, 1, -1, 1, -1, 1};
static inline simde__m128i mulByConjugate128(simde__m128i *a, simde__m128i *b, int8_t output_shift)
{
simde__m128i realPart = simde_mm_madd_epi16(*a, *b);
realPart = simde_mm_srai_epi32(realPart, output_shift);
simde__m128i imagPart = simde_mm_shufflelo_epi16(*b, SIMDE_MM_SHUFFLE(2, 3, 0, 1));
imagPart = simde_mm_shufflehi_epi16(imagPart, SIMDE_MM_SHUFFLE(2, 3, 0, 1));
imagPart = simde_mm_sign_epi16(imagPart, *(simde__m128i *)minusConjug128);
imagPart = simde_mm_madd_epi16(imagPart, *a);
imagPart = simde_mm_srai_epi32(imagPart, output_shift);
simde__m128i lowPart = simde_mm_unpacklo_epi32(realPart, imagPart);
simde__m128i highPart = simde_mm_unpackhi_epi32(realPart, imagPart);
return (simde_mm_packs_epi32(lowPart, highPart));
}
#define displaySamples128(vect) {\
simde__m128i x=vect; \
printf("vector: %s = (%hd,%hd) (%hd,%hd) (%hd,%hd) (%hd,%hd)\n", #vect, \
simde_mm_extract_epi16(x,0), \
simde_mm_extract_epi16(x,1),\
simde_mm_extract_epi16(x,2),\
simde_mm_extract_epi16(x,3),\
simde_mm_extract_epi16(x,4),\
simde_mm_extract_epi16(x,5),\
simde_mm_extract_epi16(x,6),\
simde_mm_extract_epi16(x,7));\
#define displaySamples128(vect) \
{ \
simde__m128i x = vect; \
printf("vector: %s = (%hd,%hd) (%hd,%hd) (%hd,%hd) (%hd,%hd)\n", \
#vect, \
simde_mm_extract_epi16(x, 0), \
simde_mm_extract_epi16(x, 1), \
simde_mm_extract_epi16(x, 2), \
simde_mm_extract_epi16(x, 3), \
simde_mm_extract_epi16(x, 4), \
simde_mm_extract_epi16(x, 5), \
simde_mm_extract_epi16(x, 6), \
simde_mm_extract_epi16(x, 7)); \
}
__attribute__((always_inline)) static inline int64_t simde_mm_average_sse(simde__m128i *a, int length, int shift)
{
// compute average level with shift (64-bit verstion)
simde__m128i avg128 = simde_mm_setzero_si128();
for (int i = 0; i < length >> 2; i++) {
const simde__m128i in1 = a[i];
avg128 = simde_mm_add_epi32(avg128, simde_mm_srai_epi32(simde_mm_madd_epi16(in1, in1), shift));
}
// Horizontally add pairs
// 1st [A + C, B + D]
simde__m128i sum_pairs = simde_mm_add_epi64(simde_mm_unpacklo_epi32(avg128, simde_mm_setzero_si128()), // [A, B] → [A, 0, B, 0]
simde_mm_unpackhi_epi32(avg128, simde_mm_setzero_si128()) // [C, D] → [C, 0, D, 0]
);
// 2nd [A + B + C + D, ...]
simde__m128i total_sum = simde_mm_add_epi64(sum_pairs, simde_mm_shuffle_epi32(sum_pairs, SIMDE_MM_SHUFFLE(1, 0, 3, 2)));
// Extract horizontal sum as a scalar int64_t result
return simde_mm_cvtsi128_si64(total_sum);
}
__attribute__((always_inline)) static inline int64_t simde_mm_average_avx2(simde__m256i *a, int length, int shift)
{
simde__m256i avg256 = simde_mm256_setzero_si256();
for (int i = 0; i < length >> 3; i++) {
const simde__m256i in1 = simde_mm256_loadu_si256(&a[i]); // unaligned load
avg256 = simde_mm256_add_epi32(avg256, simde_mm256_srai_epi32(simde_mm256_madd_epi16(in1, in1), shift));
}
// Split the 256-bit vector into two 128-bit halves and convert to 64-bit
// [A + E, B + F, C + G, D + H]
simde__m256i sum_pairs = simde_mm256_add_epi64(
simde_mm256_cvtepi32_epi64(simde_mm256_castsi256_si128(avg256)), // [A, B, C, D] → [A, 0, B, 0, C, 0, D, 0]
simde_mm256_cvtepi32_epi64(simde_mm256_extracti128_si256(avg256, 1)) // [E, F, G, H] → [E, 0, F, 0, G, 0, H, 0]
);
// Horizontal sum within the 256-bit vector
// [A + E + B + F, C + G + D + H]
simde__m128i total_sum = simde_mm_add_epi64(simde_mm256_castsi256_si128(sum_pairs), simde_mm256_extracti128_si256(sum_pairs, 1));
// [A + E + B + F + C + G + D + H, ...]
total_sum = simde_mm_add_epi64(total_sum, simde_mm_shuffle_epi32(total_sum, SIMDE_MM_SHUFFLE(1, 0, 3, 2)));
// Extract horizontal sum as a scalar int64_t result
return simde_mm_cvtsi128_si64(total_sum);
}
__attribute__((always_inline)) static inline int32_t simde_mm_average(simde__m128i *a, int length, int shift, int16_t scale)
{
int64_t avg = 0;
#if defined(__x86_64__) || defined(__i386__)
if (__builtin_cpu_supports("avx2")) {
avg += simde_mm_average_avx2((simde__m256i *)a, length, shift);
// tail processing by SSE
a += ((length & ~7) >> 2);
length -= (length & ~7);
}
#endif
avg += simde_mm_average_sse(a, length, shift);
return (uint32_t)(avg / scale);
}
#endif // SSE_INTRIN_H
......@@ -94,6 +94,8 @@ MessageDef *RCconfig_NR_CU_E1(const E1_t *entity)
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
/* map parameter checking array instances to parameter definition array instances */
checkedparam_t config_check_PLMNParams[] = PLMNPARAMS_CHECK;
static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams),
"config_check_PLMNParams and PLMNParams should have the same size");
for (int I = 0; I < sizeofArray(PLMNParams); ++I)
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
......
......@@ -266,9 +266,13 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc) {
paramlist_def_t ENBParamList = {ENB_CONFIG_STRING_ENB_LIST,NULL,0};
checkedparam_t config_check_CCparams[] = CCPARAMS_CHECK;
paramdef_t CCsParams[] = CCPARAMS_DESC(ccparams_lte);
static_assert(sizeofArray(config_check_CCparams) == sizeofArray(CCsParams),
"config_check_CCparams and CCsParams should have the same size");
paramlist_def_t CCsParamList = {ENB_CONFIG_STRING_COMPONENT_CARRIERS,NULL,0};
paramdef_t eMTCParams[] = EMTCPARAMS_DESC((&eMTCconfig));
checkedparam_t config_check_eMTCparams[] = EMTCPARAMS_CHECK;
static_assert(sizeofArray(config_check_eMTCparams) == sizeofArray(eMTCParams),
"config_check_eMTCparams and eMTCParamsCCsParams should have the same size");
srb1_params_t srb1_params;
memset((void *)&srb1_params,0,sizeof(srb1_params_t));
paramdef_t SRB1Params[] = SRB1PARAMS_DESC(srb1_params);
......@@ -320,6 +324,8 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc) {
paramlist_def_t PLMNParamList = {ENB_CONFIG_STRING_PLMN_LIST, NULL, 0};
/* map parameter checking array instances to parameter definition array instances */
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams),
"config_check_PLMNParams and PLMNParams should have the same size");
for (int I = 0; I < sizeofArray(PLMNParams); ++I)
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
......@@ -1910,6 +1916,8 @@ int RCconfig_M2(MessageDef *msg_p, uint32_t i) {
paramlist_def_t PLMNParamList = {ENB_CONFIG_STRING_PLMN_LIST, NULL, 0};
/* map parameter checking array instances to parameter definition array instances */
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams),
"config_check_PLMNParams and PLMNParams should have the same size");
for (int I = 0; I < sizeofArray(PLMNParams); ++I)
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
......@@ -2159,6 +2167,8 @@ int RCconfig_S1(
paramdef_t CCsParams[] = CCPARAMS_DESC(ccparams_lte);
/* map parameter checking array instances to parameter definition array instances */
checkedparam_t config_check_CCparams[] = CCPARAMS_CHECK;
static_assert(sizeofArray(config_check_CCparams) == sizeofArray(CCsParams),
"config_check_CCparams and CCsParams should have the same size");
for (int I = 0; I < sizeofArray(CCsParams); I++) {
CCsParams[I].chkPptr = &(config_check_CCparams[I]);
......@@ -2166,6 +2176,8 @@ int RCconfig_S1(
/* map parameter checking array instances to parameter definition array instances */
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams),
"config_check_PLMNParams and PLMNParams should have the same size");
for (int I = 0; I < sizeofArray(PLMNParams); ++I) {
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
......@@ -2413,6 +2425,8 @@ int RCconfig_X2(MessageDef *msg_p, uint32_t i) {
config_get(config_get_if(), ENBSParams, sizeofArray(ENBSParams), NULL);
checkedparam_t config_check_CCparams[] = CCPARAMS_CHECK;
paramdef_t CCsParams[] = CCPARAMS_DESC(ccparams_lte);
static_assert(sizeofArray(config_check_CCparams) == sizeofArray(CCsParams),
"config_check_CCparams and CCsParams should have the same size");
paramlist_def_t CCsParamList = {ENB_CONFIG_STRING_COMPONENT_CARRIERS, NULL, 0};
/* map parameter checking array instances to parameter definition array instances */
......@@ -2450,6 +2464,8 @@ int RCconfig_X2(MessageDef *msg_p, uint32_t i) {
paramlist_def_t PLMNParamList = {ENB_CONFIG_STRING_PLMN_LIST, NULL, 0};
/* map parameter checking array instances to parameter definition array instances */
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams),
"config_check_PLMNParams and PLMNParams should have the same size");
for (int I = 0; I < sizeofArray(PLMNParams); ++I)
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
......
......@@ -749,43 +749,6 @@ typedef struct ccparams_lte_s {
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } , \
{ { NULL } } \
}
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
......
......@@ -351,6 +351,7 @@ typedef struct ccparams_eMTC_s {
{ {NULL}} , \
{ {NULL}} , \
{ {NULL}} , \
{ {NULL}} , \
}
// clang-format on
......
......@@ -1118,6 +1118,8 @@ static int read_du_cell_info(configmodule_interface_t *cfg,
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
/* map parameter checking array instances to parameter definition array instances */
checkedparam_t config_check_PLMNParams[] = PLMNPARAMS_CHECK;
static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams),
"config_check_PLMNParams and PLMNParams should have the same size");
for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I)
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
......@@ -1151,6 +1153,8 @@ static int read_du_cell_info(configmodule_interface_t *cfg,
paramdef_t SNSSAIParams[] = GNBSNSSAIPARAMS_DESC;
paramlist_def_t SNSSAIParamList = {GNB_CONFIG_STRING_SNSSAI_LIST, NULL, 0};
checkedparam_t config_check_SNSSAIParams[] = SNSSAIPARAMS_CHECK;
static_assert(sizeofArray(config_check_SNSSAIParams) == sizeofArray(SNSSAIParams),
"config_check_SNSSAIParams and SNSSAIParams should have the same size");
for (int J = 0; J < sizeofArray(SNSSAIParams); ++J)
SNSSAIParams[J].chkPptr = &(config_check_SNSSAIParams[J]);
char snssaistr[MAX_OPTNAME_SIZE * 2 + 8];
......@@ -1288,6 +1292,8 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
paramdef_t GNBParams[] = GNBPARAMS_DESC;
/* map parameter checking array instances to parameter definition array instances */
checkedparam_t config_check_GNBParams[] = GNBPARAMS_CHECK;
static_assert(sizeofArray(config_check_GNBParams) == sizeofArray(GNBParams),
"config_check_GNBParams and GNBParams should have the same size");
for (int i = 0; i < sizeofArray(GNBParams); ++i)
GNBParams[i].chkPptr = &(config_check_GNBParams[i]);
config_getlist(cfg, &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
......@@ -1296,6 +1302,8 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
paramlist_def_t MacRLC_ParamList = {CONFIG_STRING_MACRLC_LIST, NULL, 0};
/* map parameter checking array instances to parameter definition array instances */
checkedparam_t config_check_MacRLCParams[] = MACRLCPARAMS_CHECK;
static_assert(sizeofArray(config_check_MacRLCParams) == sizeofArray(MacRLC_Params),
"config_check_MacRLCParams and MacRLC_Params should have the same size");
for (int i = 0; i < sizeofArray(MacRLC_Params); ++i)
MacRLC_Params[i].chkPptr = &(config_check_MacRLCParams[i]);
config_getlist(config_get_if(), &MacRLC_ParamList, MacRLC_Params, sizeofArray(MacRLC_Params), NULL);
......@@ -1906,6 +1914,8 @@ gNB_RRC_INST *RCconfig_NRRRC()
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
/* map parameter checking array instances to parameter definition array instances */
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams),
"config_check_PLMNParams and PLMNParams should have the same size");
for (int I = 0; I < sizeofArray(PLMNParams); ++I)
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
......@@ -2013,7 +2023,11 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) {
paramlist_def_t SNSSAIParamList = {GNB_CONFIG_STRING_SNSSAI_LIST, NULL, 0};
/* map parameter checking array instances to parameter definition array instances */
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams),
"config_check_PLMNParams and PLMNParams should have the same size");
checkedparam_t config_check_SNSSAIParams [] = SNSSAIPARAMS_CHECK;
static_assert(sizeofArray(config_check_SNSSAIParams) == sizeofArray(SNSSAIParams),
"config_check_SNSSAIParams and SNSSAIParams should have the same size");
for (int I = 0; I < sizeofArray(PLMNParams); ++I)
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
......@@ -2277,6 +2291,8 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) {
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
/* map parameter checking array instances to parameter definition array instances */
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams),
"config_check_PLMNParams and PLMNParams should have the same size");
for (int I = 0; I < sizeofArray(PLMNParams); ++I)
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
......
......@@ -79,6 +79,7 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config,
dci_field_t srs_resource_indicator,
nr_srs_feedback_t *srs_feedback,
const uint8_t *nrOfLayers,
int *tpmi,
uint32_t *val);
NR_PDSCH_TimeDomainResourceAllocationList_t *get_dl_tdalist(const NR_UE_DL_BWP_t *DL_BWP,
......
......@@ -894,6 +894,7 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP,
pusch_pdu,
&uldci_payload,
NULL,
NULL,
ra->Msg3_tda_id,
ra->msg3_TPC,
1, // Not toggling NDI in msg3 retransmissions
......
......@@ -782,6 +782,7 @@ void config_uldci(const NR_UE_ServingCell_Info_t *sc_info,
const nfapi_nr_pusch_pdu_t *pusch_pdu,
dci_pdu_rel15_t *dci_pdu_rel15,
nr_srs_feedback_t *srs_feedback,
int *tpmi,
int time_domain_assignment,
uint8_t tpc,
uint8_t ndi,
......@@ -830,6 +831,7 @@ void config_uldci(const NR_UE_ServingCell_Info_t *sc_info,
dci_pdu_rel15->srs_resource_indicator,
srs_feedback,
&pusch_pdu->nrOfLayers,
tpmi,
&dci_pdu_rel15->precoding_information.val);
// antenna_ports.val = 0 for transform precoder is disabled, dmrs-Type=1, maxLength=1, Rank=1/2/3/4
......
......@@ -2256,6 +2256,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot, n
uint16_t rnti = UE->rnti;
sched_ctrl->SR = false;
int *tpmi = NULL;
int8_t harq_id = sched_pusch->ul_harq_pid;
if (harq_id < 0) {
......@@ -2297,6 +2298,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot, n
* retransmissions */
cur_harq->sched_pusch.time_domain_allocation = sched_pusch->time_domain_allocation;
cur_harq->sched_pusch.nrOfLayers = sched_pusch->nrOfLayers;
cur_harq->sched_pusch.tpmi = sched_pusch->tpmi;
sched_ctrl->sched_ul_bytes += sched_pusch->tb_size;
UE->mac_stats.ul.total_rbs += sched_pusch->rbSize;
......@@ -2397,6 +2399,10 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot, n
else
pusch_pdu->data_scrambling_id = *scc->physCellId;
pusch_pdu->nrOfLayers = sched_pusch->nrOfLayers;
// If nrOfLayers is the same as in srs_feedback, we use the best TPMI, i.e. the one in srs_feedback.
// Otherwise, we use the valid TPMI that we saved in the first transmission.
if (pusch_pdu->nrOfLayers != (sched_ctrl->srs_feedback.ul_ri + 1))
tpmi = &sched_pusch->tpmi;
pusch_pdu->num_dmrs_cdm_grps_no_data = sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data;
/* FAPI: DMRS */
......@@ -2572,6 +2578,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot, n
pusch_pdu,
&uldci_payload,
&sched_ctrl->srs_feedback,
tpmi,
sched_pusch->time_domain_allocation,
UE->UE_sched_ctrl.tpc0,
cur_harq->ndi,
......
......@@ -163,6 +163,7 @@ void config_uldci(const NR_UE_ServingCell_Info_t *sc_info,
const nfapi_nr_pusch_pdu_t *pusch_pdu,
dci_pdu_rel15_t *dci_pdu_rel15,
nr_srs_feedback_t *srs_feedback,
int *tpmi,
int time_domain_assignment,
uint8_t tpc,
uint8_t ndi,
......
......@@ -422,6 +422,8 @@ typedef struct NR_sched_pusch {
int8_t ul_harq_pid;
uint8_t nrOfLayers;
int tpmi;
// time_domain_allocation is the index of a list of tda
int time_domain_allocation;
NR_tda_info_t tda_info;
......
......@@ -529,8 +529,9 @@ void trace_pdu_implementation(ws_trace_t *t)
int init_opt(void) {
paramdef_t opt_params[] = OPT_PARAMS_DESC ;
checkedparam_t opt_checkParams[] = OPTPARAMS_CHECK_DESC;
static_assert(sizeofArray(opt_params) == sizeofArray(opt_checkParams),
"opt_params and opt_checkParams should have the same size");
int sz=sizeofArray(opt_params);
AssertFatal(sz == sizeofArray(opt_checkParams), "Error in arrays size (%d!=%lu)\n", sz, sizeofArray(opt_checkParams));
config_set_checkfunctions(opt_params, opt_checkParams, sz);
config_get(config_get_if(), opt_params, sz, OPT_CONFIGPREFIX);
subframesSinceCaptureStart = 0;
......
# Plotting tools
## `ul_bler_vs_snr_graph.py`
This generates UL BLER vs SNR plots using nr_ulsim. It uses cache so subsequent runs are faster.
Assumes your nr_ulsim is in `../../cmake_targets/ran_build/build`. Run with -h flag to see options
Example graph:
![image](./example.png)
### Cache usage and modifting `nr_ulsim` command
Modify the script call to `nr_ulsim` if you want a different channel model or other flags in the `nr_ulsim` command.
Remember to clear the cache (remove `cache.pkl` from this folder) so that the results from a different run are not
taken from the cache.
Same goes for any software modifications of `nr_ulsim` - the cache is not aware of the software version used to generate
the data - remember to clear your cache manually if you are comparing different `nr_ulsim` versions.
The script also allows to skip usage of the cache with `--rerun` option.
matplotlib==3.8.3
numpy==1.21.5
#!/bin/python3
import os
import subprocess
import numpy as np
import re
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import pickle
import argparse
import concurrent.futures
import traceback
import multiprocessing
default_ulsim_cmd = "../../cmake_targets/ran_build/build/nr_ulsim -i 1,0 -t 100 -R 273"
ulsim_args = "-n {} -s {} -S {} -m {} -r {}"
def find_throughput(line):
### Example line
### SNR 10.000000: Channel BLER (0.000000e+00,-nan,-nan,-nan Channel BER (1.548551e-03,-nan,-nan,-nan) Avg round 1.00, Eff Rate 1672.0000 bits/slot, Eff Throughput 100.00, TBS 1672 bits/slot
### SNR -0.000000: Channel BLER (0.000000e+00,-nan,-nan,-nan Channel BER (1.888043e-01,-nan,-nan,-nan) Avg round 1.00, Eff Rate 2152.0000 bits/slot, Eff Throughput 100.00, TBS 2152 bits/slot
pattern = r"SNR (-?\d+.\d+).*BLER \((-?\d+\.\d*(?:[eE][+-]\d+)?),.*Eff Throughput (\d+.\d+)"
match = re.search(pattern, line)
if match:
snr, bler, thp = match.groups()
return float(snr), float(bler), float(thp)
return None, None, None
def generate_mcs_thps(ulsim_cmd_with_args, snr, mcs, num_runs = 10, num_rbs = 50, cache = {}):
thp = 0
bler = 0
num_runs_cached = 0
cache_string = "{},{},{}".format(snr, mcs, num_rbs)
if cache_string in cache:
thp, bler, num_runs_cached = cache[cache_string]
if num_runs_cached >= num_runs:
return bler, thp
num_runs_left = num_runs - num_runs_cached
ulsim_cmd_formatted = ulsim_cmd_with_args.format(num_runs_left, snr, snr+0.01, mcs, num_rbs)
print(ulsim_cmd_formatted, "result insufficient in cache, running")
process = subprocess.Popen(ulsim_cmd_formatted.split(" "), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout_data = process.communicate()[0]
output = ""
if stdout_data is not None:
output = stdout_data.decode()
for line in output.splitlines():
_snr, _bler, _thp = find_throughput(line)
if _snr is not None:
bler = (bler * num_runs_cached + _bler * num_runs_left) / num_runs
thp = (thp * num_runs_cached + _thp * num_runs_left) / num_runs
cache[cache_string] = thp, bler, num_runs
return bler, thp
print("error processing "+ ulsim_cmd_with_args)
print(output)
print(process.communicate()[1].decode())
return None, None
parser = argparse.ArgumentParser(description="UL SNR/BLER plot generator")
parser.add_argument("--snr-start", help="Starting SNR value")
parser.add_argument("--snr-stop", help="Final SNR value")
parser.add_argument("--snr-step", help="SNR step value")
parser.add_argument("--mcs-start", help="First MCS to test")
parser.add_argument("--mcs-stop", help="Last MCS to test")
parser.add_argument("--num-runs", help="Number of simulations per SNR/MCS value")
parser.add_argument("--rerun", help="Do not use cache to read data, run from scrach", action="store_true")
parser.add_argument("--num-rbs", help="Number of RBs")
parser.add_argument("--ulsim-cmd", help="ULSIM command to run. Do not use `sSrnm` flags, as these are used by the script", default=default_ulsim_cmd)
cpu_count = multiprocessing.cpu_count()
cpu_to_use = max(1, cpu_count - 2)
parser.add_argument("--num-threads", help="Number of threads to run", default=cpu_to_use)
args = parser.parse_args()
_snr_start = float(args.snr_start)
_snr_step = float(args.snr_step)
_snr_end = float(args.snr_stop) + _snr_step/2
_mcs_start = int(args.mcs_start)
_mcs_stop = int(args.mcs_stop)
_num_runs = int(args.num_runs)
_num_rbs = int(args.num_rbs)
ulsim_cmd = args.ulsim_cmd + " " + ulsim_args
num_threads = int(args.num_threads)
cmap = cm.viridis
plt.figure()
plt.ylim(-0.1, 1.1)
plt.title("BLER vs SNR for MCS{} to MCS{}, nRB={} (num_runs = {})".format(_mcs_start, _mcs_stop, _num_rbs, _num_runs))
plt.xlabel("SNR [dB]")
plt.ylabel("BLER")
cache = {}
if not args.rerun:
try:
with open("cache.pkl", "rb+") as f:
cache = pickle.load(f)
except FileNotFoundError:
pass # no cache found
snrs_list = np.arange(_snr_start, _snr_end, _snr_step)
mcss_list = np.arange(_mcs_start, _mcs_stop + 1, 1)
plot_index = 0
for mcs in mcss_list:
results = {}
with concurrent.futures.ThreadPoolExecutor(max_workers=num_threads) as executor:
result_to_snr_index = {executor.submit(generate_mcs_thps, ulsim_cmd, snrs_list[snr_index], mcs, _num_runs, _num_rbs, cache): snr_index for (snr_index, _) in enumerate(snrs_list)}
for future in concurrent.futures.as_completed(result_to_snr_index):
snr_index = result_to_snr_index[future]
bler, thp = future.result()
results[snr_index] = bler
blers = np.zeros_like(snrs_list)
for snr_index in results:
blers[snr_index] = results[snr_index]
num_plots = len(mcss_list)
percentage = float(plot_index) / max(1, (num_plots - 1))
color = cmap(percentage)
plot_index += 1
plt.plot(snrs_list, blers, label="MCS{}".format(mcs), color = color)
plt.legend()
plt.savefig('MCS={}-{},SNR={}-{},RBs={}graph.png'.format(_mcs_start, _mcs_stop, _snr_start, _snr_end, _num_rbs))
if not args.rerun:
with open("cache.pkl", "wb+") as f:
pickle.dump(cache, f)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment