Fix logging to matlab/bin file

Add Python script to plot logged buffers. Modified write_file_matlab()
to add .bin extension if binary format is selected.
This commit is contained in:
Sakthivel Velumani
2025-04-11 09:46:50 -04:00
parent 1d479b2aa9
commit 4adadedeb9
7 changed files with 1666 additions and 46 deletions
+8 -3
View File
@@ -150,14 +150,19 @@ int write_file_matlab(const char *fname, const char *vname, void *data, int leng
//printf("Writing %d elements of type %d to %s\n",length,format,fname);
const int fname_len = strlen(fname);
char write_file_name[fname_len + 10];
const char *fn_format = (format & MATLAB_RAW) ? "%s.bin" : "%s";
snprintf(write_file_name, sizeof(write_file_name), fn_format, fname);
if (format == 10 || format ==11 || format == 12 || format == 13 || format == 14 || multiVec) {
fp = fopen(fname,"a+");
fp = fopen(write_file_name, "a+");
} else if (format != 10 && format !=11 && format != 12 && format != 13 && format != 14) {
fp = fopen(fname,"w+");
fp = fopen(write_file_name, "w+");
}
if (fp== NULL) {
printf("[OPENAIR][FILE OUTPUT] Cannot open file %s\n",fname);
printf("[OPENAIR][FILE OUTPUT] Cannot open file %s\n", write_file_name);
return(-1);
}
@@ -766,10 +766,12 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
for (int a = 0; a < nbRx; a++) {
int offset = (void *)rxdataF_comp[0][a] - (void *)rxdataF_comp[0] + symbol * rx_size_symbol * sizeof(c16_t);
memcpy(ue->phy_sim_pdsch_rxdataF_comp + offset, rxdataF_comp[0][a] + symbol * rx_size_symbol, sizeof(c16_t) * rx_size_symbol);
memcpy(ue->phy_sim_pdsch_dl_ch_estimates + offset, dl_ch_estimates, pdsch_est_size * sizeof(c16_t));
memcpy((c16_t *)ue->phy_sim_pdsch_dl_ch_estimates + pdsch_est_size * a, dl_ch_estimates, pdsch_est_size * sizeof(c16_t));
}
if (ue->phy_sim_pdsch_dl_ch_estimates_ext)
memcpy(ue->phy_sim_pdsch_dl_ch_estimates_ext + symbol * rx_size_symbol, dl_ch_estimates_ext, sizeof(dl_ch_estimates_ext));
memcpy((c16_t *)ue->phy_sim_pdsch_dl_ch_estimates_ext + symbol * rx_size_symbol,
dl_ch_estimates_ext,
sizeof(dl_ch_estimates_ext));
return (0);
}
+37 -14
View File
@@ -989,6 +989,9 @@ printf("%d\n", slot);
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;
@@ -1004,9 +1007,6 @@ printf("%d\n", slot);
int harq_pid = slot;
NR_DL_UE_HARQ_t *UE_harq_process = &UE->dl_harq_processes[0][harq_pid];
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;
UE_harq_process->decodeResult = false;
round = 0;
UE_harq_process->DLround = round;
@@ -1105,10 +1105,10 @@ printf("%d\n", slot);
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);
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];
@@ -1292,15 +1292,38 @@ printf("%d\n", slot);
}
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, 1, 1);
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, 1, 1);
LOG_M("rxF0.m","rxF0", UE->phy_sim_rxdataF, frame_parms->samples_per_slot_wCP, 1, 1);
LOG_M("rxF_ext.m","rxFe",UE->phy_sim_pdsch_rxdataF_ext,g_rbSize*12*14,1,1);
LOG_M("chestF0.m","chF0",UE->phy_sim_pdsch_dl_ch_estimates_ext,g_rbSize*12*14,1,1);
write_output("rxF_comp.m","rxFc",UE->phy_sim_pdsch_rxdataF_comp,N_RB_DL*12*14,1,1);
LOG_M("rxF_llr.m","rxFllr",UE->phy_sim_pdsch_llr,available_bits,1,0);
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;
}
+30 -27
View File
@@ -240,6 +240,7 @@ int main(int argc, char *argv[])
int threadCnt=0;
int max_ldpc_iterations = 5;
int num_antennas_per_thread = 1;
uint32_t log_format = 0;
if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == 0) {
exit_fun("[NR_ULSIM] Error, configuration module init failed\n");
}
@@ -251,8 +252,7 @@ int main(int argc, char *argv[])
InitSinLUT();
int c;
while ((c = getopt(argc, argv, "--:O:a:b:c:d:ef:g:h:i:k:m:n:p:q:r:s:t:u:v:w:y:z:A:C:F:G:H:I:M:N:PR:S:T:U:L:ZW:E:X:")) != -1) {
while ((c = getopt(argc, argv, "--:O:a:b:c:d:ef:g:h:i:jk:m:n:p:q:r:s:t:u:v:w:y:z:A:C:F:G:H:I:M:N:PR:S:T:U:L:ZW:E:X:")) != -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')
@@ -346,7 +346,11 @@ int main(int argc, char *argv[])
i+=2;
} while (optarg[i-1] == ',');
break;
case 'j':
log_format |= MATLAB_RAW;
break;
case 'k':
printf("Setting threequarter_fs_flag\n");
openair0_cfg[0].threequarter_fs= 1;
@@ -524,6 +528,7 @@ int main(int argc, char *argv[])
printf("-g Channel model configuration. Arguments list: Number of arguments = 3, {Channel model: [A] TDLA30, [B] TDLB100, [C] TDLC300}, {Correlation: [l] Low, [m] Medium, [h] High}, {Maximum Doppler shift} e.g. -g A,l,10\n");
printf("-h This message\n");
printf("-i Change channel estimation technique. Arguments list: Number of arguments=2, Frequency domain {0:Linear interpolation, 1:PRB based averaging}, Time domain {0:Estimates of last DMRS symbol, 1:Average of DMRS symbols}. e.g. -i 1,0\n");
printf("-j Save signal buffers in binary format.");
printf("-k 3/4 sampling\n");
printf("-m MCS value\n");
printf("-n Number of trials to simulate\n");
@@ -560,7 +565,7 @@ int main(int argc, char *argv[])
}
}
logInit();
set_glog(loglvl);
@@ -1215,12 +1220,12 @@ int main(int argc, char *argv[])
phy_procedures_nrUE_TX(UE, &UE_proc, &phy_data);
if (n_trials == 1) {
LOG_M("txsig0.m", "txs0", &UE->common_vars.txData[0][slot_offset], slot_length, 1, 1);
LOG_M("txsig0.m", "txs0", &UE->common_vars.txData[0][slot_offset], slot_length, 1, 1 | log_format);
if (precod_nbr_layers > 1) {
LOG_M("txsig1.m", "txs1", &UE->common_vars.txData[1][slot_offset], slot_length, 1, 1);
if (precod_nbr_layers == 4) {
LOG_M("txsig2.m", "txs2", &UE->common_vars.txData[2][slot_offset], slot_length, 1, 1);
LOG_M("txsig3.m", "txs3", &UE->common_vars.txData[3][slot_offset], slot_length, 1, 1);
LOG_M("txsig1.m", "txs1", &UE->common_vars.txData[1][slot_offset], slot_length, 1, 1 | log_format);
if (precod_nbr_layers == 4) {
LOG_M("txsig2.m", "txs2", &UE->common_vars.txData[2][slot_offset], slot_length, 1, 1 | log_format);
LOG_M("txsig3.m", "txs3", &UE->common_vars.txData[3][slot_offset], slot_length, 1, 1 | log_format);
}
}
}
@@ -1294,16 +1299,16 @@ int main(int argc, char *argv[])
ul_proc_error = phy_procedures_gNB_uespec_RX(gNB, frame, slot, &UL_INFO);
if (n_trials == 1 && round == 0) {
LOG_M("rxsig0.m", "rx0", &rxdata[0][slot_offset], slot_length, 1, 1);
LOG_M("rxsigF0.m", "rxsF0", gNB->common_vars.rxdataF[0][0], 14 * frame_parms->ofdm_symbol_size, 1, 1);
LOG_M("rxsig0.m", "rx0", &rxdata[0][slot_offset], slot_length, 1, 1 | log_format);
LOG_M("rxsigF0.m", "rxsF0", gNB->common_vars.rxdataF[0][0], 14 * frame_parms->ofdm_symbol_size, 1, 1 | log_format);
if (precod_nbr_layers > 1) {
LOG_M("rxsig1.m", "rx1", &rxdata[1][slot_offset], slot_length, 1, 1);
LOG_M("rxsigF1.m", "rxsF1", gNB->common_vars.rxdataF[0][1], 14 * frame_parms->ofdm_symbol_size, 1, 1);
LOG_M("rxsigF1.m", "rxsF1", gNB->common_vars.rxdataF[0][1], 14 * frame_parms->ofdm_symbol_size, 1, 1 | log_format);
if (precod_nbr_layers == 4) {
LOG_M("rxsig2.m", "rx2", &rxdata[2][slot_offset], slot_length, 1, 1);
LOG_M("rxsig3.m", "rx3", &rxdata[3][slot_offset], slot_length, 1, 1);
LOG_M("rxsigF2.m", "rxsF2", gNB->common_vars.rxdataF[0][2], 14 * frame_parms->ofdm_symbol_size, 1, 1);
LOG_M("rxsigF3.m", "rxsF3", gNB->common_vars.rxdataF[0][3], 14 * frame_parms->ofdm_symbol_size, 1, 1);
LOG_M("rxsigF2.m", "rxsF2", gNB->common_vars.rxdataF[0][2], 14 * frame_parms->ofdm_symbol_size, 1, 1 | log_format);
LOG_M("rxsigF3.m", "rxsF3", gNB->common_vars.rxdataF[0][3], 14 * frame_parms->ofdm_symbol_size, 1, 1 | log_format);
}
}
}
@@ -1317,71 +1322,69 @@ int main(int argc, char *argv[])
&pusch_vars->ul_ch_estimates[0][start_symbol * frame_parms->ofdm_symbol_size],
frame_parms->ofdm_symbol_size,
1,
1);
1 | log_format);
LOG_M("rxsigF0_comp.m",
"rxsF0_comp",
&pusch_vars->rxdataF_comp[0][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
nb_symb_sch * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size)),
1,
1);
1 | log_format);
if (precod_nbr_layers == 2) {
LOG_M("chestF3.m",
"chF3",
&pusch_vars->ul_ch_estimates[3][start_symbol * frame_parms->ofdm_symbol_size],
frame_parms->ofdm_symbol_size,
1,
1);
1 | log_format);
LOG_M("rxsigF2_comp.m",
"rxsF2_comp",
&pusch_vars->rxdataF_comp[2][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
nb_symb_sch * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size)),
1,
1);
1 | log_format);
}
if (precod_nbr_layers == 4) {
LOG_M("chestF5.m",
"chF5",
&pusch_vars->ul_ch_estimates[5][start_symbol * frame_parms->ofdm_symbol_size],
frame_parms->ofdm_symbol_size,
1,
1);
1 | log_format);
LOG_M("chestF10.m",
"chF10",
&pusch_vars->ul_ch_estimates[10][start_symbol * frame_parms->ofdm_symbol_size],
frame_parms->ofdm_symbol_size,
1,
1);
1 | log_format);
LOG_M("chestF15.m",
"chF15",
&pusch_vars->ul_ch_estimates[15][start_symbol * frame_parms->ofdm_symbol_size],
frame_parms->ofdm_symbol_size,
1,
1);
1 | log_format);
LOG_M("rxsigF4_comp.m",
"rxsF4_comp",
&pusch_vars->rxdataF_comp[4][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
nb_symb_sch * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size)),
1,
1);
1 | log_format);
LOG_M("rxsigF8_comp.m",
"rxsF8_comp",
&pusch_vars->rxdataF_comp[8][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
nb_symb_sch * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size)),
1,
1);
1 | log_format);
LOG_M("rxsigF12_comp.m",
"rxsF12_comp",
&pusch_vars->rxdataF_comp[12][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
nb_symb_sch * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size)),
1,
1);
1 | log_format);
}
LOG_M("rxsigF0_llr.m",
@@ -1389,7 +1392,7 @@ int main(int argc, char *argv[])
&pusch_vars->llr[0],
precod_nbr_layers * (nb_symb_sch - 1) * NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,
1,
0);
0 | log_format);
}
if ((ulsch_gNB->last_iteration_cnt >= ulsch_gNB->max_ldpc_iterations) || ul_proc_error == 1) {
+13
View File
@@ -19,3 +19,16 @@ Same goes for any software modifications of `nr_ulsim` - the cache is not aware
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.
## `dl_graph.py`
This generates plots from data saved from nr_dlsim. It takes data in two formats:
1. Plots frequency domain channel estimates, constellation diagram and LLRs from data read in binary format. The data is generated from `nr_dlsim -w`
2. Plots BER (other also possible) from CSV data generated by `nr_dlsim -Z`.
The plots are saved in three formats: `.png`, `.pdf` and `.svg`.
### Example graphs:
#### BER
![image](./ber_compare.svg)
File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 39 KiB

+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env python
# coding: utf-8
import numpy as np
import matplotlib.pyplot as plt
import argparse
import pandas
def save_fig(fig:plt.figure, figName:str):
fig.savefig(figName + '.pdf')
fig.savefig(figName + '.png')
fig.savefig(figName + '.svg')
# Channel Frequency Response
def channel_est(dataPath):
binfile = dataPath + 'chestF0_ext_s1.m.bin'
data = np.fromfile(binfile,dtype=np.int16)
dataCmp = data[0::2] + 1j*data[1::2]
fig = plt.gcf()
plt.plot(np.abs(dataCmp))
save_fig(fig, 'channel_est')
plt.close(fig)
# Constellation
def constellation(dataPath):
binfile = dataPath + 'rxF_comp_s1.m.bin'
data = np.fromfile(binfile,dtype=np.int16)
dataCmp = data[0::2] + 1j*data[1::2]
fig = plt.gcf()
plt.scatter(np.real(dataCmp),np.imag(dataCmp))
save_fig(fig, 'constellation')
plt.close(fig)
# LLR
def llr(dataPath):
binfile = dataPath + 'rxF_llr.m.bin'
data = np.fromfile(binfile,dtype=np.int16)
fig = plt.gcf()
plt.plot(data,'*')
save_fig(fig, 'llr')
plt.close(fig)
# BER from data in CSV files generated by nr_dlsim
def ber(dataPath, csvFiles):
d0 = pandas.read_csv(dataPath + csvFiles[0] + '.csv')
ax = d0.plot(x='SNR',y='channel_ber_0',logy=True,label=csvFiles[0])
plt.ylabel('BER')
for i in range(1,len(csvFiles)):
d = pandas.read_csv(dataPath + csvFiles[i] + '.csv')
d.plot(ax=ax,x='SNR',y='channel_ber_0',logy=True,label=csvFiles[i],grid=True)
fig = ax.figure
save_fig(fig, 'ber_compare')
plt.close(fig)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="DL plot generator")
parser.add_argument('--data-path', help='Path to directory containing data', default='../../cmake_targets/ran_build/build/')
parser.add_argument('--csv-data', nargs='+' ,help='CSV file name without extension (generated from nr_dlsim with -Z option)')
parser.add_argument('--ber-compare', help='Compare BER from multiple CSV files', action='store_true')
args = parser.parse_args()
channel_est(args.data_path)
constellation(args.data_path)
llr(args.data_path)
if args.ber_compare:
ber(args.data_path, args.csv_data)