Compare commits

...

10 Commits

Author SHA1 Message Date
Sakthivel Velumani
9cb59cf391 PUSCH compensate amplitude 2025-07-10 16:38:59 -04:00
Sakthivel Velumani
1afd63a998 tmp: 2x2 MMSE works with fading
scale H^H by det
2025-07-10 16:38:59 -04:00
Sakthivel Velumani
55bfa2cee3 tmp: split comp functions, MMSE has bugs need to fix it 2025-07-10 16:38:59 -04:00
Sakthivel Velumani
1b5dc509e3 PDSCH compensate channel amplitude
The PDSCH channel compensation function compensates only phase and not
the magnitude. Compensating the phase is not necessasary because the
channel magnitude of each RE is used as LLR thresholds. Hence, the LLRs
that are close to origin have the same likelihood as when received
samples are compensated for magnitude.

However, compensating magnitude shows a clean constellation and LLR
plot. So this commit adds it as a optional feature.
2025-07-10 16:38:59 -04:00
Sakthivel Velumani
47448f95ce Add dlsim test case for 256 qam & fading channel
So far the performance of 256 qam with fading channel was very bad with
nearly 100% bler. It was similar for other mod order > 2. With the
current fix in compensation and LLR computation, the performance is now
in acceptable range. Hence, a new test case is added with TDL-A channel.
2025-07-10 16:38:59 -04:00
Sakthivel Velumani
7ff9d015e6 Fix bug in LLR threshold buffer
The LLR threshold buffers hold only for one symbol but the LLRs are
computed for all symbols together. So only the threshold of last symbol
was used for computing LLR for all other symbols.

This commit calls nr_dlsch_llr for each symbol togther with rest of
nr_rx_pdsch() and calls nr_dlsch_layer_demapping at the last symbol.
2025-07-10 16:11:09 -04:00
Sakthivel Velumani
a901342138 ulsch dump buff 2025-07-10 02:23:10 -04:00
Sakthivel Velumani
d5e97ca6fe Dlsim dump processing buffers
Write extracted rxF buffer to output bin file.
Fix offset in writing rxF buffer.
2025-07-10 02:23:07 -04:00
Sakthivel Velumani
fe92feaecc Dlsim read IQ from external gNB
Read SIB1 and RRCSetup message from binary file and configure the UE
before processing the IQ samples.
2025-05-15 17:46:41 -04:00
Sakthivel Velumani
ccf2d6f615 Fix alignment of LLR buffer in UE 2025-05-09 01:40:27 -04:00
11 changed files with 751 additions and 183 deletions

View File

@@ -225,14 +225,16 @@
<desc>nr_dlsim Test cases. (Test1: 106 PRBs 50 PDSCH-PRBs MCS Index 27),
(Test2: 106 PRBs 50 PDSCH-PRBs MCS Index 16),
(Test3: 106 MCS-TABLE 256 QAM MCS Index 26),
(Test4: MCS 0, low SNR performance),
(Test5: 4x4 MIMO, 1 Layer),
(Test6: 4x4 MIMO, 2 Layers),
(Test7: 4x4 MIMO, 4 Layers)</desc>
(Test4: 106 MCS-TABLE 256 QAM MCS Index 22, Fading Channel),
(Test5: MCS 0, low SNR performance),
(Test6: 4x4 MIMO, 1 Layer),
(Test7: 4x4 MIMO, 2 Layers),
(Test8: 4x4 MIMO, 4 Layers)</desc>
<main_exec>nr_dlsim</main_exec>
<main_exec_args>-n100 -e27 -s30
-n100 -e16 -s11 -S13
-n100 -q1 -e26 -s30
-n100 -q1 -e22 -s25 -gA
-n100 -e0 -t95 -S-1.0 -i 2 1 0
-n10 -s20 -U 3 0 0 2 -gA -x1 -y4 -z4
-n10 -s20 -U 3 0 0 2 -gA -x2 -y4 -z4

View File

@@ -225,6 +225,26 @@ static void nr_ulsch_channel_level(int size_est,
}
static inline void compensate_amplitude(const simde__m256i *h2, simde__m256i *rF, const int amp)
{
const simde__m128i *rF_128 = (const simde__m128i *)rF;
const simde__m128i *h2_128 = (const simde__m128i *)h2;
const simde__m256 ones = simde_mm256_set1_ps((float)amp);
// sample 0, 1, 2, 3
const simde__m256i o0 =
simde_mm256_cvtps_epi32(simde_mm256_mul_ps(simde_mm256_div_ps(simde_mm256_cvtepi32_ps(simde_mm256_cvtepi16_epi32(rF_128[0])),
simde_mm256_cvtepi32_ps(simde_mm256_cvtepi16_epi32(h2_128[0]))),
ones));
// sample 4, 5, 6, 7
const simde__m256i o1 =
simde_mm256_cvtps_epi32(simde_mm256_mul_ps(simde_mm256_div_ps(simde_mm256_cvtepi32_ps(simde_mm256_cvtepi16_epi32(rF_128[1])),
simde_mm256_cvtepi32_ps(simde_mm256_cvtepi16_epi32(h2_128[1]))),
ones));
//*((simde__m256i *)rF) = simde_mm256_packs_epi32(o0, o1);
*((simde__m128i *)rF) = simde_mm_packs_epi32(*((simde__m128i *)&o0), *(((simde__m128i *)&o0)+1));
*(((simde__m128i *)rF)+1) = simde_mm_packs_epi32(*((simde__m128i *)&o1), *(((simde__m128i *)&o1)+1));
}
static void nr_ulsch_channel_compensation(c16_t *rxFext,
c16_t *chFext,
c16_t *ul_ch_maga,
@@ -236,6 +256,7 @@ static void nr_ulsch_channel_compensation(c16_t *rxFext,
nfapi_nr_pusch_pdu_t* rel15_ul,
uint32_t symbol,
uint32_t buffer_length,
int32_t maxh_avg,
uint32_t output_shift)
{
int mod_order = rel15_ul->qam_mod_order;
@@ -247,19 +268,25 @@ static void nr_ulsch_channel_compensation(c16_t *rxFext,
simde__m256i QAM_ampc_256 = simde_mm256_setzero_si256();
if (mod_order == 4) {
QAM_ampa_256 = simde_mm256_set1_epi16(QAM16_n1);
const int16_t amp = (int16_t)((maxh_avg >> output_shift) * 2 / sqrt(10));
QAM_ampa_256 = simde_mm256_set1_epi16(amp);
QAM_ampb_256 = simde_mm256_setzero_si256();
QAM_ampc_256 = simde_mm256_setzero_si256();
}
else if (mod_order == 6) {
QAM_ampa_256 = simde_mm256_set1_epi16(QAM64_n1);
QAM_ampb_256 = simde_mm256_set1_epi16(QAM64_n2);
const int16_t amp = (int16_t)((maxh_avg >> output_shift) * 4 / sqrt(42));
const int16_t ampb = (int16_t)((maxh_avg >> output_shift) * 2 / sqrt(42));
QAM_ampa_256 = simde_mm256_set1_epi16(amp);
QAM_ampb_256 = simde_mm256_set1_epi16(ampb);
QAM_ampc_256 = simde_mm256_setzero_si256();
}
else if (mod_order == 8) {
QAM_ampa_256 = simde_mm256_set1_epi16(QAM256_n1);
QAM_ampb_256 = simde_mm256_set1_epi16(QAM256_n2);
QAM_ampc_256 = simde_mm256_set1_epi16(QAM256_n3);
const int16_t amp = (int16_t)((maxh_avg >> output_shift) * 8 / sqrt(170));
const int16_t ampb = (int16_t)((maxh_avg >> output_shift) * 4 / sqrt(170));
const int16_t ampc = (int16_t)((maxh_avg >> output_shift) * 2 / sqrt(170));
QAM_ampa_256 = simde_mm256_set1_epi16(amp);
QAM_ampb_256 = simde_mm256_set1_epi16(ampb);
QAM_ampc_256 = simde_mm256_set1_epi16(ampc);
}
for (int aatx = 0; aatx < nrOfLayers; aatx++) {
@@ -277,19 +304,32 @@ static void nr_ulsch_channel_compensation(c16_t *rxFext,
simde__m256i comp = oai_mm256_cpx_mult_conj(chF_256[i], rxF_256[i], output_shift);
rxComp_256[i] = simde_mm256_add_epi16(rxComp_256[i], comp);
simde__m256i h2 = simde_mm256_srai_epi32(simde_mm256_madd_epi16(chF_256[i], chF_256[i]), output_shift);
h2 = simde_mm256_packs_epi32(h2, h2);
// sum channel magnitude of all antenna (|h1|^2 + |h2|^2 + ...)
h2 = simde_mm256_unpacklo_epi16(h2, h2);
const int amp = maxh_avg >> output_shift;
compensate_amplitude(&h2, rxComp_256 + i, amp);
if (mod_order > 2) {
simde__m256i mag = oai_mm256_smadd(chF_256[i], chF_256[i], output_shift); // |h|^2
// pack and duplicate
mag = simde_mm256_packs_epi32(mag, mag);
mag = simde_mm256_unpacklo_epi16(mag, mag);
rxF_ch_maga_256[i] = simde_mm256_add_epi16(rxF_ch_maga_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampa_256));
//rxF_ch_maga_256[i] = simde_mm256_add_epi16(rxF_ch_maga_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampa_256));
rxF_ch_maga_256[i] = QAM_ampa_256;
if (mod_order > 4)
rxF_ch_magb_256[i] = simde_mm256_add_epi16(rxF_ch_magb_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampb_256));
if (mod_order > 4) {
//rxF_ch_magb_256[i] = simde_mm256_add_epi16(rxF_ch_magb_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampb_256));
rxF_ch_magb_256[i] = QAM_ampb_256;
}
if (mod_order > 6)
rxF_ch_magc_256[i] = simde_mm256_add_epi16(rxF_ch_magc_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampc_256));
if (mod_order > 6) {
//rxF_ch_magc_256[i] = simde_mm256_add_epi16(rxF_ch_magc_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampc_256));
rxF_ch_magc_256[i] = QAM_ampc_256;
}
}
}
if (rho != NULL) {
@@ -984,8 +1024,30 @@ static void inner_rx(PHY_VARS_gNB *gNB,
rel15_ul,
symbol,
buffer_length,
pusch_vars->maxh_avgs,
output_shift);
#define DUMP_PUSCH_BUFF 1
#if DUMP_PUSCH_BUFF
const uint32_t numValidREs = dmrs_symbol_flag ? (rel15_ul->dmrs_config_type == NFAPI_NR_DMRS_TYPE1)
? rel15_ul->rb_size * (12 - 6 * rel15_ul->num_dmrs_cdm_grps_no_data)
: rel15_ul->rb_size * (12 - 4 * rel15_ul->num_dmrs_cdm_grps_no_data)
: 12 * rel15_ul->rb_size;
const int decimation = 1;
const uint32_t format = 1 | MATLAB_RAW;
for (int r = 0; r < nb_rx_ant; r++) {
char fName[50];
for (int l = 0; l < nb_layer; l++) {
snprintf(fName, sizeof(fName), "chestF_ext_l%d_r%d_s%d.m", l, r, symbol);
LOG_M(fName, "chest_ext", chFext[l][r], numValidREs, decimation, format);
snprintf(fName, sizeof(fName), "rxF_comp_l%d_s%d.m", l, symbol);
LOG_M(fName, "rxF_comp", pusch_vars->rxdataF_comp[l * nb_rx_ant] + symbol * buffer_length, numValidREs, decimation, format);
}
snprintf(fName, sizeof(fName), "rxF_ext_r%d_s%d.m", r, symbol);
LOG_M(fName, "rxf_ext", rxFext[r], numValidREs, decimation, format);
}
#endif
if (nb_layer == 1 && rel15_ul->transform_precoding == transformPrecoder_enabled && rel15_ul->qam_mod_order <= 6) {
if (rel15_ul->qam_mod_order > 2)
nr_freq_equalization(frame_parms,
@@ -1368,6 +1430,8 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
avgs = cmax(avgs, avg[nl * frame_parms->nb_antennas_rx + aarx]);
pusch_vars->maxh_avgs = avgs;
if (rel15_ul->nrOfLayers == 2 && rel15_ul->qam_mod_order > 6)
pusch_vars->log2_maxh = (log2_approx(avgs) >> 1) - 3; // for MMSE
else if (rel15_ul->nrOfLayers == 2)

View File

@@ -191,7 +191,8 @@ static void nr_dlsch_channel_compensation(uint32_t rx_size_symbol,
unsigned char mod_order,
unsigned short nb_rb,
unsigned char output_shift,
PHY_NR_MEASUREMENTS *measurements);
PHY_NR_MEASUREMENTS *measurements,
int32_t ch_mag2_avg);
/** \brief This function computes the average channel level over all allocated RBs and antennas (TX/RX) in order to compute output shift for compensated signal
@param dl_ch_estimates_ext Channel estimates in allocated RBs
@@ -226,6 +227,34 @@ static void nr_dlsch_detection_mrc(uint32_t rx_size_symbol,
int32_t dl_ch_magr[][n_rx][rx_size_symbol],
unsigned char symbol,
int length);
static void nr_dlsch_ch_mag(const uint32_t rx_size_symbol,
const int nbRx,
int32_t dl_ch_mag[][nbRx][rx_size_symbol],
int32_t dl_ch_magb[][nbRx][rx_size_symbol],
int32_t dl_ch_magr[][nbRx][rx_size_symbol],
const unsigned char mod_order,
const uint8_t n_layers,
const int length,
const unsigned char output_shift,
const int32_t ch_mag2_avg);
static void nr_dlsch_comp_mag(const uint32_t rx_size_symbol,
const int nbRx,
int32_t rxdataF_comp[][nbRx][rx_size_symbol * NR_SYMBOLS_PER_SLOT],
const int32_t dl_ch_estimates_ext[][rx_size_symbol],
const uint8_t n_layers,
const unsigned char symbol,
const int length,
const unsigned char output_shift,
const int32_t ch_mag2_avg);
static void nr_dlsch_compensate_channel_phase(const uint32_t rx_size_symbol,
const c16_t rxdataF_ext[][rx_size_symbol],
const int32_t dl_ch_estimates_ext[][rx_size_symbol],
const uint16_t n_rx,
const uint16_t n_layers,
const uint32_t length,
const uint32_t symbol,
const uint32_t output_shift,
int32_t rxdataF_comp[][n_rx][rx_size_symbol * NR_SYMBOLS_PER_SLOT]);
static bool overlap_csi_symbol(fapi_nr_dl_config_csirs_pdu_rel15_t *csi_pdu, int symbol)
{
@@ -312,11 +341,13 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
unsigned char harq_pid,
uint32_t pdsch_est_size,
int32_t dl_ch_estimates[][pdsch_est_size],
int layer_llr_size,
int16_t layer_llr[][layer_llr_size],
int16_t *llr[2],
uint32_t dl_valid_re[NR_SYMBOLS_PER_SLOT],
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP],
uint32_t llr_offset[NR_SYMBOLS_PER_SLOT],
int32_t *log2_maxh,
int32_t *ch_avgs,
int rx_size_symbol,
int nbRx,
int32_t rxdataF_comp[][nbRx][rx_size_symbol * NR_SYMBOLS_PER_SLOT],
@@ -434,6 +465,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
//----------------------------------------------------------
const int n_rx = frame_parms->nb_antennas_rx;
const bool meas_enabled = cpumeas(CPUMEAS_GETSTATE);
int log2_maxh = 0;
{
start_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS);
@@ -473,10 +505,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
ue->phy_cpu_stats.cpu_time_stats[DLSCH_EXTRACT_RBS_STATS].p_time / (cpuf * 1000.0));
}
if (ue->phy_sim_pdsch_rxdataF_ext)
for (unsigned char aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
int offset = ((void *)rxdataF_ext[aarx] - (void *)rxdataF_ext) + symbol * rx_size_symbol;
memcpy(ue->phy_sim_pdsch_rxdataF_ext + offset, rxdataF_ext, rx_size_symbol * sizeof(c16_t));
}
memcpy(ue->phy_sim_pdsch_rxdataF_ext + symbol * sizeof(rxdataF_ext), rxdataF_ext, sizeof(rxdataF_ext));
nb_re_pdsch = (pilots == 1) ? ((config_type == NFAPI_NR_DMRS_TYPE1) ? nb_rb_pdsch * (12 - 6 * dlsch_config->n_dmrs_cdm_groups)
: nb_rb_pdsch * (12 - 4 * dlsch_config->n_dmrs_cdm_groups))
@@ -507,26 +536,25 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
nr_dlsch_channel_level(rx_size_symbol, dl_ch_estimates_ext, frame_parms->nb_antennas_rx, nl, avg, nb_re_pdsch);
else
LOG_E(NR_PHY, "Average channel level is 0: nb_rb_pdsch = %d, nb_re_pdsch = %d\n", nb_rb_pdsch, nb_re_pdsch);
int avgs = 0;
int32_t median[MAX_ANT][MAX_ANT];
for (int aatx = 0; aatx < nl; aatx++)
for (int aarx = 0; aarx < n_rx; aarx++) {
avgs = cmax(avgs, avg[aatx][aarx]);
*ch_avgs = cmax(*ch_avgs, avg[aatx][aarx]);
LOG_D(PHY, "nb_rb %d avg_%d_%d Power per SC is %d\n", nb_rb_pdsch, aarx, aatx, avg[aatx][aarx]);
LOG_D(PHY, "avgs Power per SC is %d\n", avgs);
LOG_D(PHY, "avgs Power per SC is %d\n", *ch_avgs);
median[aatx][aarx] = avg[aatx][aarx];
}
if (nl > 1) {
nr_dlsch_channel_level_median(rx_size_symbol, dl_ch_estimates_ext, median, nl, n_rx, nb_re_pdsch);
for (int aatx = 0; aatx < nl; aatx++) {
for (int aarx = 0; aarx < n_rx; aarx++) {
avgs = cmax(avgs, median[aatx][aarx]);
*ch_avgs = cmax(*ch_avgs, median[aatx][aarx]);
}
}
}
*log2_maxh = (log2_approx(avgs) / 2) + 1;
LOG_D(PHY, "[DLSCH] AbsSubframe %d.%d log2_maxh = %d (%d)\n", frame % 1024, nr_slot_rx, *log2_maxh, avgs);
}
log2_maxh = (log2_approx(*ch_avgs) / 2);
LOG_D(PHY, "[DLSCH] AbsSubframe %d.%d log2_maxh = %d (%d)\n", frame % 1024, nr_slot_rx, log2_maxh, *ch_avgs);
stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_LEVEL_STATS);
if (meas_enabled) {
LOG_D(PHY,
@@ -547,24 +575,15 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
//----------------------------------------------------------
// Disable correlation measurement for optimizing UE
start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_COMPENSATION_STATS);
nr_dlsch_channel_compensation(rx_size_symbol,
nbRx,
rxdataF_ext,
dl_ch_estimates_ext,
dl_ch_mag,
dl_ch_magb,
dl_ch_magr,
rxdataF_comp,
NULL,
frame_parms,
nl,
symbol,
nb_re_pdsch,
first_symbol_flag,
dlsch_config->qamModOrder,
nb_rb_pdsch,
*log2_maxh,
measurements); // log2_maxh+I0_shift
nr_dlsch_compensate_channel_phase(rx_size_symbol,
rxdataF_ext,
dl_ch_estimates_ext,
nbRx,
nl,
nb_re_pdsch,
symbol,
log2_maxh,
rxdataF_comp);
stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_COMPENSATION_STATS);
if (meas_enabled) {
LOG_D(PHY,
@@ -573,7 +592,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
nr_slot_rx,
slot,
symbol,
*log2_maxh,
log2_maxh,
ue->phy_cpu_stats.cpu_time_stats[DLSCH_CHANNEL_COMPENSATION_STATS].p_time / (cpuf * 1000.0));
}
// Please keep it: useful for debugging
@@ -609,22 +628,36 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
dl_ch_magr,
symbol,
nb_re_pdsch);
if (nl >= 2) // Apply MMSE for 2, 3, and 4 Tx layers
if (nb_re_pdsch)
nr_dlsch_mmse(rx_size_symbol,
n_rx,
nl,
rxdataF_comp,
dl_ch_mag,
dl_ch_magb,
dl_ch_magr,
dl_ch_estimates_ext,
nb_rb_pdsch,
dlsch_config->qamModOrder,
*log2_maxh,
symbol,
nb_re_pdsch,
nvar);
}
if (nl > 1) { // Apply MMSE for 2, 3, and 4 Tx layers
AssertFatal(n_rx > 1, "Number of Rx antennas less than layers\n");
if (nb_re_pdsch)
nr_dlsch_mmse(rx_size_symbol,
n_rx,
nl,
rxdataF_comp,
dl_ch_mag,
dl_ch_magb,
dl_ch_magr,
dl_ch_estimates_ext,
nb_rb_pdsch,
dlsch_config->qamModOrder,
log2_maxh,
symbol,
nb_re_pdsch,
nvar);
} else {
nr_dlsch_comp_mag(rx_size_symbol, n_rx, rxdataF_comp, dl_ch_estimates_ext, nl, symbol, nb_re_pdsch, log2_maxh, *ch_avgs);
nr_dlsch_ch_mag(rx_size_symbol,
n_rx,
dl_ch_mag,
dl_ch_magb,
dl_ch_magr,
dlsch_config->qamModOrder,
nl,
nb_re_pdsch,
log2_maxh,
*ch_avgs);
}
stop_meas_nr_ue_phy(ue, DLSCH_MRC_MMSE_STATS);
@@ -671,47 +704,28 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
dlsch);
dl_valid_re[symbol] -= ptrs_re_per_slot[0][symbol];
}
start_meas_nr_ue_phy(ue, DLSCH_LLR_STATS);
nr_dlsch_llr(rx_size_symbol,
nbRx,
layer_llr_size,
layer_llr,
rxdataF_comp,
dl_ch_mag[0][0],
dl_ch_magb[0][0],
dl_ch_magr[0][0],
dlsch0_harq,
dlsch1_harq,
symbol,
dl_valid_re[symbol],
dlsch,
llr_offset[symbol]);
if (symbol < startSymbIdx + nbSymb - 1) // up to the penultimate symbol
llr_offset[symbol + 1] = dl_valid_re[symbol] * dlsch_config->qamModOrder + llr_offset[symbol];
stop_meas_nr_ue_phy(ue, DLSCH_LLR_STATS);
/* at last symbol in a slot calculate LLR's for whole slot */
if(symbol == (startSymbIdx + nbSymb - 1)) {
const uint32_t rx_llr_layer_size = (G + dlsch[0].Nl - 1) / dlsch[0].Nl;
if (dlsch[0].Nl == 0 || rx_llr_layer_size == 0 || rx_llr_layer_size > 10 * 1000 * 1000) {
LOG_E(PHY, "rx_llr_layer_size %d, G %d, Nl, %d, discarding this pdsch\n", rx_llr_layer_size, G, dlsch[0].Nl);
return -1;
}
int16_t layer_llr[dlsch[0].Nl][rx_llr_layer_size];
for(int i = startSymbIdx; i < startSymbIdx + nbSymb; i++) {
/* Calculate LLR's for each symbol */
start_meas_nr_ue_phy(ue, DLSCH_LLR_STATS);
nr_dlsch_llr(rx_size_symbol,
nbRx,
rx_llr_layer_size,
layer_llr,
rxdataF_comp,
dl_ch_mag[0][0],
dl_ch_magb[0][0],
dl_ch_magr[0][0],
dlsch0_harq,
dlsch1_harq,
i,
dl_valid_re[i],
dlsch,
llr_offset[i]);
if (i < startSymbIdx + nbSymb - 1) // up to the penultimate symbol
llr_offset[i + 1] = dl_valid_re[i] * dlsch_config->qamModOrder + llr_offset[i];
stop_meas_nr_ue_phy(ue, DLSCH_LLR_STATS);
}
if (symbol == (startSymbIdx + nbSymb - 1)) {
start_meas_nr_ue_phy(ue, DLSCH_LAYER_DEMAPPING);
nr_dlsch_layer_demapping(llr,
dlsch[0].Nl,
dlsch_config->qamModOrder,
G,
codeword_TB0,
codeword_TB1,
rx_llr_layer_size,
layer_llr);
nr_dlsch_layer_demapping(llr, dlsch[0].Nl, dlsch_config->qamModOrder, G, codeword_TB0, codeword_TB1, layer_llr_size, layer_llr);
stop_meas_nr_ue_phy(ue, DLSCH_LAYER_DEMAPPING);
/*
for (int i=0; i < 2; i++){
@@ -763,12 +777,16 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
if (ue->phy_sim_pdsch_rxdataF_comp)
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);
for (int l = 0; l < nl; l++) {
int offset = (void *)rxdataF_comp[l][a] - (void *)rxdataF_comp[0] + symbol * rx_size_symbol * sizeof(c16_t);
memcpy(ue->phy_sim_pdsch_rxdataF_comp + offset,
rxdataF_comp[l][a] + symbol * rx_size_symbol,
sizeof(c16_t) * rx_size_symbol);
}
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((c16_t *)ue->phy_sim_pdsch_dl_ch_estimates_ext + symbol * rx_size_symbol,
memcpy(ue->phy_sim_pdsch_dl_ch_estimates_ext + symbol * sizeof(dl_ch_estimates_ext),
dl_ch_estimates_ext,
sizeof(dl_ch_estimates_ext));
return (0);
@@ -825,6 +843,172 @@ void nr_dlsch_deinterleaving(uint8_t symbol,
// Pre-processing for LLR computation
//==============================================================================================
static inline void compensate_amplitude(const simde__m128i *h2, simde__m128i *rF, const int amp)
{
const simde__m128i rF_128 = *rF;
const simde__m128i h2_128 = *h2;
const simde__m128 ones = simde_mm_set1_ps((float)amp);
// sample 0, 1
const simde__m128i o0 = simde_mm_cvtps_epi32(simde_mm_mul_ps(
simde_mm_div_ps(simde_mm_cvtepi32_ps(simde_mm_cvtepi16_epi32(rF_128)), simde_mm_cvtepi32_ps(simde_mm_cvtepi16_epi32(h2_128))),
ones));
// sample 2, 3
const simde__m128i o1 = simde_mm_cvtps_epi32(
simde_mm_mul_ps(simde_mm_div_ps(simde_mm_cvtepi32_ps(simde_mm_cvtepi16_epi32(simde_mm_shuffle_epi32(rF_128, 0b1110))),
simde_mm_cvtepi32_ps(simde_mm_cvtepi16_epi32(simde_mm_shuffle_epi32(h2_128, 0b1110)))),
ones));
*((simde__m128i *)rF) = simde_mm_packs_epi32(o0, o1);
}
static void nr_dlsch_ch_mag(const uint32_t rx_size_symbol,
const int nbRx,
int32_t dl_ch_mag[][nbRx][rx_size_symbol],
int32_t dl_ch_magb[][nbRx][rx_size_symbol],
int32_t dl_ch_magr[][nbRx][rx_size_symbol],
const unsigned char mod_order,
const uint8_t n_layers,
const int length,
const unsigned char output_shift,
const int32_t ch_mag2_avg)
{
const uint32_t nb_rb_0 = length / 12 + ((length % 12) ? 1 : 0);
for (int l = 0; l < n_layers; l++) {
simde__m128i QAM_amp128 = {0}, QAM_amp128b = {0}, QAM_amp128r = {0};
if (mod_order == 4) {
const int16_t amp = (int16_t)((ch_mag2_avg >> output_shift) * 2 / sqrt(10));
QAM_amp128 = simde_mm_set1_epi16(amp); // 2/sqrt(10)
QAM_amp128b = simde_mm_setzero_si128();
QAM_amp128r = simde_mm_setzero_si128();
} else if (mod_order == 6) {
const int16_t amp = (int16_t)((ch_mag2_avg >> output_shift) * 4 / sqrt(42));
const int16_t ampb = (int16_t)((ch_mag2_avg >> output_shift) * 2 / sqrt(42));
QAM_amp128 = simde_mm_set1_epi16(amp);
QAM_amp128b = simde_mm_set1_epi16(ampb);
QAM_amp128r = simde_mm_setzero_si128();
} else if (mod_order == 8) {
const int16_t amp = (int16_t)((ch_mag2_avg >> output_shift) * 8 / sqrt(170));
const int16_t ampb = (int16_t)((ch_mag2_avg >> output_shift) * 4 / sqrt(170));
const int16_t ampr = (int16_t)((ch_mag2_avg >> output_shift) * 2 / sqrt(170));
QAM_amp128 = simde_mm_set1_epi16(amp);
QAM_amp128b = simde_mm_set1_epi16(ampb);
QAM_amp128r = simde_mm_set1_epi16(ampr);
}
for (int aarx = 0; aarx < nbRx; aarx++) {
simde__m128i *dl_ch_mag128 = (simde__m128i *)dl_ch_mag[l][aarx];
simde__m128i *dl_ch_mag128b = (simde__m128i *)dl_ch_magb[l][aarx];
simde__m128i *dl_ch_mag128r = (simde__m128i *)dl_ch_magr[l][aarx];
for (int rb = 0; rb < nb_rb_0; rb++) {
if (mod_order > 2) {
// get channel amplitude if not QPSK
dl_ch_mag128[0] = QAM_amp128;
dl_ch_mag128b[0] = QAM_amp128b;
dl_ch_mag128r[0] = QAM_amp128r;
dl_ch_mag128[1] = dl_ch_mag128[2] = dl_ch_mag128[0];
dl_ch_mag128b[1] = dl_ch_mag128b[2] = dl_ch_mag128b[0];
dl_ch_mag128r[1] = dl_ch_mag128r[2] = dl_ch_mag128r[0];
}
dl_ch_mag128 += 3;
dl_ch_mag128b += 3;
dl_ch_mag128r += 3;
}
}
}
}
/*
* Compesate for channel amplitude only in case of single layer
*/
static void nr_dlsch_comp_mag(const uint32_t rx_size_symbol,
const int nbRx,
int32_t rxdataF_comp[][nbRx][rx_size_symbol * NR_SYMBOLS_PER_SLOT],
const int32_t dl_ch_estimates_ext[][rx_size_symbol],
const uint8_t n_layers,
const unsigned char symbol,
const int length,
const unsigned char output_shift,
const int32_t ch_mag2_avg)
{
const uint32_t nb_rb_0 = length / 12 + ((length % 12) ? 1 : 0);
/* we could also call MMSE directly here but I'm not sure if the complexity is justified given there is only one layer
need to check the performance difference after rewritting MMSE funtion to handle one layer
*/
AssertFatal(n_layers == 1, "Call nr_dlsch_mmse() for more than 1 layer\n");
for (int l = 0; l < n_layers; l++) {
// holds sum of channel magnitude of all antennas for each RE
c16_t h2[rx_size_symbol];
memset(h2, 0, sizeof(h2));
for (int_fast8_t aarx = 0; aarx < nbRx; aarx++) {
simde__m128i *h2_128 = (simde__m128i *)h2;
const simde__m128i *dl_ch128 = (const simde__m128i *)dl_ch_estimates_ext[(l * nbRx) + aarx];
for (int rb = 0; rb < nb_rb_0; rb++) {
simde__m128i h2_0 = simde_mm_srai_epi32(simde_mm_madd_epi16(dl_ch128[0], dl_ch128[0]), output_shift);
simde__m128i h2_1 = simde_mm_srai_epi32(simde_mm_madd_epi16(dl_ch128[1], dl_ch128[1]), output_shift);
simde__m128i h2_2 = simde_mm_srai_epi32(simde_mm_madd_epi16(dl_ch128[2], dl_ch128[2]), output_shift);
h2_0 = simde_mm_packs_epi32(h2_0, h2_1);
// sum channel magnitude of all antenna (|h1|^2 + |h2|^2 + ...)
h2_128[0] = simde_mm_add_epi16(h2_128[0], simde_mm_unpacklo_epi16(h2_0, h2_0));
h2_128[1] = simde_mm_add_epi16(h2_128[1], simde_mm_unpackhi_epi16(h2_0, h2_0));
h2_2 = simde_mm_packs_epi32(h2_2, h2_2);
h2_128[2] = simde_mm_add_epi16(h2_128[2], simde_mm_unpacklo_epi16(h2_2, h2_2));
h2_128 += 3;
dl_ch128 += 3;
}
}
simde__m128i *rxdataF_comp128 = (simde__m128i *)(rxdataF_comp[l][0] + symbol * rx_size_symbol);
simde__m128i *h2_128 = (simde__m128i *)h2;
const int h2_avg = ch_mag2_avg >> output_shift;
for (int rb = 0; rb < nb_rb_0; rb++) {
/* When using int16_t arithmetic to compensate channel magnitude, there is a chance of overflow when channel amplitude
response has large dynamic range. So we have to use either int32 or floating point arithmetic. We use floating point. */
compensate_amplitude(h2_128, rxdataF_comp128, h2_avg);
compensate_amplitude(h2_128 + 1, rxdataF_comp128 + 1, h2_avg);
compensate_amplitude(h2_128 + 2, rxdataF_comp128 + 2, h2_avg);
h2_128 += 3;
rxdataF_comp128 += 3;
}
}
}
static void nr_dlsch_compensate_channel_phase(const uint32_t rx_size_symbol,
const c16_t rxdataF_ext[][rx_size_symbol],
const int32_t dl_ch_estimates_ext[][rx_size_symbol],
const uint16_t n_rx,
const uint16_t n_layers,
const uint32_t length,
const uint32_t symbol,
const uint32_t output_shift,
int32_t rxdataF_comp[][n_rx][rx_size_symbol * NR_SYMBOLS_PER_SLOT])
{
const uint32_t nb_rb_0 = length / 12 + ((length % 12) ? 1 : 0);
for (int_fast16_t l = 0; l < n_layers; l++) {
for (int_fast16_t aarx = 0; aarx < n_rx; aarx++) {
simde__m128i *dl_ch128 = (simde__m128i *)dl_ch_estimates_ext[(l * n_rx) + aarx];
simde__m128i *rxdataF128 = (simde__m128i *)rxdataF_ext[aarx];
simde__m128i *rxdataF_comp128 = (simde__m128i *)(rxdataF_comp[l][aarx] + symbol * rx_size_symbol);
for (int_fast32_t rb = 0; rb < nb_rb_0; rb++) {
// Multiply received data by conjugated channel
rxdataF_comp128[0] = oai_mm_cpx_mult_conj(dl_ch128[0], rxdataF128[0], output_shift);
rxdataF_comp128[1] = oai_mm_cpx_mult_conj(dl_ch128[1], rxdataF128[1], output_shift);
rxdataF_comp128[2] = oai_mm_cpx_mult_conj(dl_ch128[2], rxdataF128[2], output_shift);
dl_ch128 += 3;
rxdataF128 += 3;
rxdataF_comp128 += 3;
}
}
}
}
static void nr_dlsch_channel_compensation(uint32_t rx_size_symbol,
int nbRx,
c16_t rxdataF_ext[][rx_size_symbol],
@@ -842,26 +1026,33 @@ static void nr_dlsch_channel_compensation(uint32_t rx_size_symbol,
unsigned char mod_order,
unsigned short nb_rb,
unsigned char output_shift,
PHY_NR_MEASUREMENTS *measurements)
PHY_NR_MEASUREMENTS *measurements,
int32_t ch_mag2_avg)
{
simde__m128i *dl_ch128, *dl_ch128_2, *dl_ch_mag128, *dl_ch_mag128b, *dl_ch_mag128r, *rxdataF128, *rxdataF_comp128, *rho128;
simde__m128i mmtmpD0, mmtmpD1, QAM_amp128 = {0}, QAM_amp128b = {0}, QAM_amp128r = {0};
simde__m128i QAM_amp128 = {0}, QAM_amp128b = {0}, QAM_amp128r = {0};
uint32_t nb_rb_0 = length / 12 + ((length % 12) ? 1 : 0);
for (int l = 0; l < n_layers; l++) {
if (mod_order == 4) {
QAM_amp128 = simde_mm_set1_epi16(QAM16_n1); // 2/sqrt(10)
const int16_t amp = (int16_t)((ch_mag2_avg >> output_shift) * 2 / sqrt(10));
QAM_amp128 = simde_mm_set1_epi16(amp); // 2/sqrt(10)
QAM_amp128b = simde_mm_setzero_si128();
QAM_amp128r = simde_mm_setzero_si128();
} else if (mod_order == 6) {
QAM_amp128 = simde_mm_set1_epi16(QAM64_n1); //
QAM_amp128b = simde_mm_set1_epi16(QAM64_n2);
const int16_t amp = (int16_t)((ch_mag2_avg >> output_shift) * 4 / sqrt(42));
const int16_t ampb = (int16_t)((ch_mag2_avg >> output_shift) * 2 / sqrt(42));
QAM_amp128 = simde_mm_set1_epi16(amp);
QAM_amp128b = simde_mm_set1_epi16(ampb);
QAM_amp128r = simde_mm_setzero_si128();
} else if (mod_order == 8) {
QAM_amp128 = simde_mm_set1_epi16(QAM256_n1);
QAM_amp128b = simde_mm_set1_epi16(QAM256_n2);
QAM_amp128r = simde_mm_set1_epi16(QAM256_n3);
const int16_t amp = (int16_t)((ch_mag2_avg >> output_shift) * 8 / sqrt(170));
const int16_t ampb = (int16_t)((ch_mag2_avg >> output_shift) * 4 / sqrt(170));
const int16_t ampr = (int16_t)((ch_mag2_avg >> output_shift) * 2 / sqrt(170));
QAM_amp128 = simde_mm_set1_epi16(amp);
QAM_amp128b = simde_mm_set1_epi16(ampb);
QAM_amp128r = simde_mm_set1_epi16(ampr);
}
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
@@ -876,41 +1067,13 @@ static void nr_dlsch_channel_compensation(uint32_t rx_size_symbol,
if (mod_order > 2) {
// get channel amplitude if not QPSK
mmtmpD0 = simde_mm_madd_epi16(dl_ch128[0], dl_ch128[0]);
mmtmpD0 = simde_mm_srai_epi32(mmtmpD0, output_shift);
dl_ch_mag128[0] = QAM_amp128;
dl_ch_mag128b[0] = QAM_amp128b;
dl_ch_mag128r[0] = QAM_amp128r;
mmtmpD1 = simde_mm_madd_epi16(dl_ch128[1], dl_ch128[1]);
mmtmpD1 = simde_mm_srai_epi32(mmtmpD1, output_shift);
mmtmpD0 = simde_mm_packs_epi32(mmtmpD0, mmtmpD1); //|H[0]|^2 |H[1]|^2 |H[2]|^2 |H[3]|^2 |H[4]|^2 |H[5]|^2 |H[6]|^2 |H[7]|^2
// store channel magnitude here in a new field of dlsch
dl_ch_mag128[0] = simde_mm_unpacklo_epi16(mmtmpD0, mmtmpD0);
dl_ch_mag128b[0] = dl_ch_mag128[0];
dl_ch_mag128r[0] = dl_ch_mag128[0];
dl_ch_mag128[0] = simde_mm_mulhrs_epi16(dl_ch_mag128[0], QAM_amp128);
dl_ch_mag128b[0] = simde_mm_mulhrs_epi16(dl_ch_mag128b[0], QAM_amp128b);
dl_ch_mag128r[0] = simde_mm_mulhrs_epi16(dl_ch_mag128r[0], QAM_amp128r);
dl_ch_mag128[1] = simde_mm_unpackhi_epi16(mmtmpD0, mmtmpD0);
dl_ch_mag128b[1] = dl_ch_mag128[1];
dl_ch_mag128r[1] = dl_ch_mag128[1];
dl_ch_mag128[1] = simde_mm_mulhrs_epi16(dl_ch_mag128[1], QAM_amp128);
dl_ch_mag128b[1] = simde_mm_mulhrs_epi16(dl_ch_mag128b[1], QAM_amp128b);
dl_ch_mag128r[1] = simde_mm_mulhrs_epi16(dl_ch_mag128r[1], QAM_amp128r);
mmtmpD0 = simde_mm_madd_epi16(dl_ch128[2], dl_ch128[2]);
mmtmpD0 = simde_mm_srai_epi32(mmtmpD0, output_shift);
mmtmpD1 = simde_mm_packs_epi32(mmtmpD0, mmtmpD0);
dl_ch_mag128[2] = simde_mm_unpacklo_epi16(mmtmpD1, mmtmpD1);
dl_ch_mag128b[2] = dl_ch_mag128[2];
dl_ch_mag128r[2] = dl_ch_mag128[2];
dl_ch_mag128[2] = simde_mm_mulhrs_epi16(dl_ch_mag128[2], QAM_amp128);
dl_ch_mag128b[2] = simde_mm_mulhrs_epi16(dl_ch_mag128b[2], QAM_amp128b);
dl_ch_mag128r[2] = simde_mm_mulhrs_epi16(dl_ch_mag128r[2], QAM_amp128r);
dl_ch_mag128[1] = dl_ch_mag128[2] = dl_ch_mag128[0];
dl_ch_mag128b[1] = dl_ch_mag128b[2] = dl_ch_mag128b[0];
dl_ch_mag128r[1] = dl_ch_mag128r[2] = dl_ch_mag128r[0];
}
// Multiply received data by conjugated channel
@@ -918,6 +1081,26 @@ static void nr_dlsch_channel_compensation(uint32_t rx_size_symbol,
rxdataF_comp128[1] = oai_mm_cpx_mult_conj(dl_ch128[1], rxdataF128[1], output_shift);
rxdataF_comp128[2] = oai_mm_cpx_mult_conj(dl_ch128[2], rxdataF128[2], output_shift);
// Compensate channel amplitude
simde__m128i h2_0 = simde_mm_srai_epi32(simde_mm_madd_epi16(dl_ch128[0], dl_ch128[0]), output_shift);
simde__m128i h2_1 = simde_mm_srai_epi32(simde_mm_madd_epi16(dl_ch128[1], dl_ch128[1]), output_shift);
simde__m128i h2_2 = simde_mm_srai_epi32(simde_mm_madd_epi16(dl_ch128[2], dl_ch128[2]), output_shift);
h2_0 = simde_mm_packs_epi32(h2_0, h2_1);
h2_0 = simde_mm_unpacklo_epi16(h2_0, h2_0);
h2_1 = simde_mm_unpackhi_epi16(h2_0, h2_0);
h2_2 = simde_mm_packs_epi32(h2_2, h2_2);
h2_2 = simde_mm_unpacklo_epi16(h2_2, h2_2);
/* When using int16_t arithmetic to compensate channel magnitude, there is a chance of overflow when channel amplitude
response has large dynamic range. So we have to use either int32 or floating point arithmetic. We use floating point. */
const int h2_avg = ch_mag2_avg >> output_shift;
compensate_amplitude(&h2_0, rxdataF_comp128, h2_avg);
compensate_amplitude(&h2_1, rxdataF_comp128 + 1, h2_avg);
compensate_amplitude(&h2_2, rxdataF_comp128 + 2, h2_avg);
print_shorts(" Rx signal:=", (int16_t *)rxdataF_comp128);
print_shorts(" Rx signal:=", (int16_t *)(rxdataF_comp128 + 1));
print_shorts(" Rx signal:=", (int16_t *)(rxdataF_comp128 + 2));
dl_ch128 += 3;
dl_ch_mag128 += 3;
dl_ch_mag128b += 3;
@@ -1510,6 +1693,62 @@ void nr_conjch0_mult_ch1(c16_t *ch0, c16_t *ch1, c16_t *ch0conj_ch1, unsigned sh
mult_cpx_conj_vector(ch0, ch1, ch0conj_ch1, 12 * nb_rb, output_shift0);
}
static void nr_matrix_scale_determin(const int size,
const int length,
const int nb_rb_0,
const int shift,
const c16_t determin[NR_NB_SC_PER_RB*nb_rb_0],
c16_t *matrix[size][size])
{
/*
Dividing two complex numbers:
a + bi (a + bi)(c - di)
------ = ----------------
c + di (c + di)(c - di)
ac + bd bc - ad
= --------- + ----------- i
c^2 + d^2 c^2 + d^2
*/
// average of determin
const int16_t x = factor2(length);
const int16_t y = (length) >> x;
simde__m128i *cd = (simde__m128i *)determin;
const int32_t det_avg = simde_mm_average(cd, NR_NB_SC_PER_RB * nb_rb_0, x, y);
const int32_t log2_det_avg = log2_approx(det_avg) / 2;
for (int_fast16_t r = 0; r < size; r++) {
for (int_fast16_t c = 0; c < size; c++) {
// (a + bi)(c - di)
mult_cpx_conj_vector(determin, matrix[r][c], matrix[r][c], NR_NB_SC_PER_RB * nb_rb_0, log2_det_avg);
// scale by 1/(c^2 + d^2)
simde__m128i *ab = (simde__m128i *)matrix[r][c];
cd = (simde__m128i *)determin;
for (int_fast16_t rb = 0; rb < nb_rb_0; rb++) {
simde__m128i c2d2_unpack[3];
c2d2_unpack[0] = simde_mm_srai_epi32(simde_mm_madd_epi16(cd[0], cd[0]), log2_det_avg);
c2d2_unpack[1] = simde_mm_srai_epi32(simde_mm_madd_epi16(cd[1], cd[1]), log2_det_avg);
c2d2_unpack[2] = simde_mm_srai_epi32(simde_mm_madd_epi16(cd[2], cd[2]), log2_det_avg);
simde__m128i c2d2[3];
const simde__m128i c2d2_01 = simde_mm_packs_epi32(c2d2_unpack[0], c2d2_unpack[1]);
c2d2[0] = simde_mm_unpacklo_epi16(c2d2_01, c2d2_01);
c2d2[1] = simde_mm_unpackhi_epi16(c2d2_01, c2d2_01);
const simde__m128i c2d2_2 = simde_mm_packs_epi32(c2d2_unpack[2], c2d2_unpack[2]);
c2d2[2] = simde_mm_unpacklo_epi16(c2d2_2, c2d2_2);
const int32_t c2d2_avg = 1 << shift;
compensate_amplitude(c2d2, ab, c2d2_avg);
compensate_amplitude(c2d2 + 1, ab + 1, c2d2_avg);
compensate_amplitude(c2d2 + 2, ab + 2, c2d2_avg);
cd += 3;
ab += 3;
}
}
}
}
/*
* MMSE Rx function: up to 4 layers
*/
@@ -1587,6 +1826,9 @@ static void nr_dlsch_mmse(uint32_t rx_size_symbol,
fp_flag, // fixed point flag
shift - (fp_flag == 1 ? 2 : 0)); // the out put is Q15
// scale inv(H*H) by determinant
nr_matrix_scale_determin(nl, length, nb_rb_0, shift /*- (fp_flag == 1 ? 2 : 0)*/, determ_fin, inv_H_h_H);
// multiply Matrix inversion pf H_h_H by the rx signal vector
c16_t outtemp[12 * nb_rb_0] __attribute__((aligned(32)));
//Allocate rxdataF for zforcing out

View File

@@ -302,6 +302,8 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
unsigned char harq_pid,
uint32_t pdsch_est_size,
int32_t dl_ch_estimates[][pdsch_est_size],
int layer_llr_size,
int16_t layer_llr[][layer_llr_size],
int16_t *llr[2],
uint32_t dl_valid_re[NR_SYMBOLS_PER_SLOT],
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP],

View File

@@ -305,6 +305,8 @@ typedef struct {
int32_t **rxdataF_comp;
/// \f$\log_2(\max|H_i|^2)\f$
int16_t log2_maxh;
/// max|H_i|^2
int32_t maxh_avgs;
/// measured RX power based on DRS
uint32_t ulsch_power[8];
/// total signal over antennas

View File

@@ -601,7 +601,15 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
uint32_t dl_valid_re[NR_SYMBOLS_PER_SLOT] = {0};
uint32_t llr_offset[NR_SYMBOLS_PER_SLOT] = {0};
int32_t log2_maxh = 0;
const uint32_t rx_llr_layer_size = (G + dlsch[0].Nl - 1) / dlsch[0].Nl;
if (dlsch[0].Nl == 0 || rx_llr_layer_size == 0 || rx_llr_layer_size > 10 * 1000 * 1000) {
LOG_E(PHY, "rx_llr_layer_size %d, G %d, Nl, %d, discarding this pdsch\n", rx_llr_layer_size, G, dlsch[0].Nl);
return -1;
}
__attribute__((aligned(32))) int16_t layer_llr[dlsch[0].Nl][rx_llr_layer_size];
int32_t ch_avgs = 0;
start_meas_nr_ue_phy(ue, RX_PDSCH_STATS);
for (int m = dlschCfg->start_symbol; m < (dlschCfg->number_symbols + dlschCfg->start_symbol); m++) {
bool first_symbol_flag = false;
@@ -618,11 +626,13 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
harq_pid,
pdsch_est_size,
pdsch_dl_ch_estimates,
rx_llr_layer_size,
layer_llr,
llr,
dl_valid_re,
rxdataF,
llr_offset,
&log2_maxh,
&ch_avgs,
rx_size_symbol,
ue->frame_parms.nb_antennas_rx,
rxdataF_comp,
@@ -1008,6 +1018,8 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_
phy_pdcch_config->nb_search_space = 0;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PDCCH, VCD_FUNCTION_OUT);
TracyCZoneEnd(ctx);
if (ue->phy_sim_rxdataF)
memcpy(ue->phy_sim_rxdataF, rxdataF[0], sizeof(int32_t) * nb_symb_pdcch * ue->frame_parms.ofdm_symbol_size);
return sampleShift;
}
@@ -1132,9 +1144,11 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
}
if (ue->phy_sim_rxdataF)
memcpy(ue->phy_sim_rxdataF, rxdataF, sizeof(int32_t)*rxdataF_sz*ue->frame_parms.nb_antennas_rx);
memcpy(ue->phy_sim_rxdataF + start_symb_sch * ue->frame_parms.ofdm_symbol_size * sizeof(c16_t),
&rxdataF[0][start_symb_sch * ue->frame_parms.ofdm_symbol_size],
sizeof(int32_t) * nb_symb_sch * ue->frame_parms.ofdm_symbol_size);
if (ue->phy_sim_pdsch_llr)
memcpy(ue->phy_sim_pdsch_llr, llr[0], sizeof(int16_t)*rx_llr_buf_sz);
memcpy(ue->phy_sim_pdsch_llr, llr[0], sizeof(int16_t) * rx_llr_buf_sz);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_OUT);
for (int i=0; i<nb_codewords; i++)

View File

@@ -38,6 +38,7 @@
#include "LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h"
#include "LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
#include "NR_BCCH-BCH-Message.h"
#include "NR_DL-CCCH-Message.h"
#include "NR_BWP-Downlink.h"
#include "NR_CellGroupConfig.h"
#include "NR_MAC_COMMON/nr_mac.h"
@@ -90,6 +91,7 @@
#include "utils.h"
#define inMicroS(a) (((double)(a))/(get_cpu_freq_GHz()*1000.0))
#include "SIMULATION/LTE_PHY/common_sim.h"
#include "openair2/COMMON/mac_messages_types.h"
const char *__asan_default_options()
{
@@ -295,6 +297,70 @@ void validate_input_pmi(nfapi_nr_config_request_scf_t *gNB_config,
num_antenna_ports, pmi_pdu->num_ant_ports, pmi);
}
typedef struct {
uint64_t dl_freq;
uint64_t frame;
uint64_t slot;
uint64_t cellid;
uint64_t rnti;
} param_from_file_t;
void load_sib1_config(const uint8_t *sdu, const uint32_t sdu_size, NR_UE_MAC_INST_t *mac)
{
NR_BCCH_DL_SCH_Message_t *bcch_message = NULL;
asn_dec_rval_t dec_rval = uper_decode_complete(NULL,
&asn_DEF_NR_BCCH_DL_SCH_Message,
(void **)&bcch_message,
(const void *)sdu,
sdu_size);
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
printf("Failed to decode BCCH_DLSCH_MESSAGE (%zu bits)\n", dec_rval.consumed);
// free the memory
SEQUENCE_free(&asn_DEF_NR_BCCH_DL_SCH_Message, (void *)bcch_message, 1);
return;
}
xer_fprint(stdout, &asn_DEF_NR_BCCH_DL_SCH_Message,(void *)bcch_message);
NR_SIB1_t *sib1 = bcch_message->message.choice.c1->choice.systemInformationBlockType1;
NR_ServingCellConfigCommonSIB_t *scc = sib1->servingCellConfigCommon;
int bwp_id = 0;
config_common_ue_sa(mac, scc, 0);
configure_common_BWP_dl(mac, bwp_id, &scc->downlinkConfigCommon.initialDownlinkBWP);
}
void load_rrcsetup_config(const uint8_t *sdu, const uint32_t sdu_size, NR_UE_NR_Capability_t *ue_cap, NR_UE_MAC_INST_t *mac)
{
NR_DL_CCCH_Message_t *dl_ccch_msg = NULL;
asn_dec_rval_t dec_rval = uper_decode(NULL, &asn_DEF_NR_DL_CCCH_Message, (void **)&dl_ccch_msg, sdu, sdu_size, 0, 0);
xer_fprint(stdout, &asn_DEF_NR_DL_CCCH_Message, (void *)dl_ccch_msg);
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
printf("Failed to decode DL-CCCH-Message (%zu bytes)\n", dec_rval.consumed);
return;
}
if (dl_ccch_msg->message.present != NR_DL_CCCH_MessageType_PR_c1) {
printf("No message present %d\n", dl_ccch_msg->message.present);
return;
} else {
if (dl_ccch_msg->message.choice.c1->present != NR_DL_CCCH_MessageType__c1_PR_rrcSetup) {
printf("Expected rrcSetup but got %d\n", dl_ccch_msg->message.choice.c1->present);
return;
}
}
NR_RRCSetup_t *rrcSetup = dl_ccch_msg->message.choice.c1->choice.rrcSetup;
OCTET_STRING_t *mcg = &rrcSetup->criticalExtensions.choice.rrcSetup->masterCellGroup;
NR_CellGroupConfig_t *cellGroupConfig = NULL;
uper_decode(NULL,
&asn_DEF_NR_CellGroupConfig, //might be added prefix later
(void **)&cellGroupConfig,
(uint8_t *)mcg->buf,
mcg->size, 0, 0);
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig);
nr_rrc_mac_config_req_cg(0, 0, cellGroupConfig, ue_cap);
}
configmodule_interface_t *uniqCfg = NULL;
int main(int argc, char **argv)
@@ -392,7 +458,7 @@ int main(int argc, char **argv)
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) {
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:wT: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' */
@@ -657,6 +723,26 @@ printf("%d\n", slot);
get_softmodem_params()->do_ra = 0;
IS_SOFTMODEM_DLSIM = true;
NRRrcMacCcchDataInd has_sib1;
NRRrcMacCcchDataInd has_rrcSetup;
param_from_file_t in_params = {0};
uint64_t input_sample_size = 0;
c16_t *input_slot_iq = NULL;
if (input_fd) {
int err = 0;
err += fread(&in_params, sizeof(in_params), 1, input_fd);
err += fread(&has_sib1.sdu_size, sizeof(has_sib1.sdu_size), 1, input_fd);
err += fread(&has_sib1.sdu, has_sib1.sdu_size, 1, input_fd);
err += fread(&has_rrcSetup.sdu_size, sizeof(has_rrcSetup.sdu_size), 1, input_fd);
err += fread(&has_rrcSetup.sdu, has_rrcSetup.sdu_size, 1, input_fd);
err += fread(&input_sample_size, sizeof(input_sample_size), 1, input_fd);
printf("input sample size %ld\n",input_sample_size);
input_slot_iq = malloc16_clear(sizeof(*input_slot_iq) * input_sample_size);
err += fread(input_slot_iq, sizeof(c16_t), input_sample_size, input_fd);
if (err == 0)
printf("Error reading from file\n");
}
if (snr1set==0)
snr1 = snr0+10;
@@ -920,15 +1006,16 @@ printf("%d\n", slot);
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);
if (input_fd == NULL) {
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);
@@ -1027,7 +1114,7 @@ printf("%d\n", slot);
//n_errors2 = 0;
//n_alamouti = 0;
n_false_positive = 0;
if (n_trials== 1) num_rounds = 1;
if (input_fd != NULL || 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;
@@ -1192,11 +1279,31 @@ printf("%d\n", slot);
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);
if (input_fd) {
UE_proc.frame_rx = frame = in_params.frame;
UE_proc.nr_slot_rx = slot = in_params.slot;
UE->frame_parms.Nid_cell = in_params.cellid;
UE->frame_parms.dl_CarrierFreq = in_params.dl_freq;
UE_mac->crnti = in_params.rnti;
load_sib1_config(has_sib1.sdu, has_sib1.sdu_size, UE_mac);
load_rrcsetup_config(has_rrcSetup.sdu, has_rrcSetup.sdu_size, UE_Capability_nr, UE_mac);
nr_ue_phy_config_request(&UE_mac->phy_config);
init_symbol_rotation(&UE->frame_parms);
dl_config.sfn = frame;
dl_config.slot = slot;
ue_dci_configuration(UE_mac, &dl_config, frame, slot);
nr_ue_scheduled_response(&scheduled_response);
slot_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0);
slot_length = slot_offset - frame_parms->get_samples_slot_timestamp(slot-1,frame_parms,0);
memcpy(&UE->common_vars.rxdata[0][slot_offset], input_slot_iq, sizeof(c16_t) * slot_length);
} else {
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);
@@ -1213,11 +1320,11 @@ printf("%d\n", slot);
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;
uint16_t length_dmrs = get_num_dmrs(dlsch0->dlsch_config.dlDmrsSymbPos);
uint16_t nb_rb = dlsch0->dlsch_config.number_rbs;
uint8_t nb_re_dmrs = dlsch0->dlsch_config.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 = dlsch0->dlsch_config.qamModOrder;
uint8_t nb_symb_sch = dlsch0->dlsch_config.number_symbols;
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) {
@@ -1342,23 +1449,38 @@ printf("%d\n", slot);
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);
for (int l = 0; l < g_nrOfLayers; l++) {
for (int r = 0; r < n_rx; r++) {
const int s = rel15->StartSymbolIndex;
const int n = rel15->NrOfSymbols;
for (int i = s; i < s + n; i++) {
const uint32_t dmrsBitMap = phy_data.dlsch[0].dlsch_config.dlDmrsSymbPos;
const uint32_t dmrsCfg = phy_data.dlsch[0].dlsch_config.dmrsConfigType;
const uint32_t nrb = phy_data.dlsch[0].dlsch_config.number_rbs;
const uint32_t ncdmg = phy_data.dlsch[0].dlsch_config.n_dmrs_cdm_groups;
const uint32_t numValidReSym = ((dmrsBitMap >> i) & 1)
? ((dmrsCfg == NFAPI_NR_DMRS_TYPE1) ? nrb * (12 - 6 * ncdmg) : nrb * (12 - 4 * ncdmg))
: (nrb * 12);
char fName[50];
snprintf(fName, sizeof(fName), "chestF_ext_l%d_r%d_s%d.m", l, r, i);
uint32_t buff_offset = (i * g_nrOfLayers * n_rx * numReSym) + (l * n_rx * numReSym) + (r * numReSym);
LOG_M(fName,
"chF0_ext",
((c16_t *)UE->phy_sim_pdsch_dl_ch_estimates_ext) + buff_offset,
numValidReSym,
dec,
op_format);
snprintf(fName, sizeof(fName), "rxF_comp_l%d_s%d.m", l, i);
LOG_M(fName, "rxFc", ((c16_t *)UE->phy_sim_pdsch_rxdataF_comp) + (l * NR_SYMBOLS_PER_SLOT * numReSym) + (i * numReSym), numValidReSym, dec, op_format);
if (l == 0) {
snprintf(fName, sizeof(fName), "rxF_ext_r%d_s%d.m", r, i);
buff_offset = (i * n_rx * numReSym) + (r * numReSym);
LOG_M(fName, "rxFext", ((c16_t *)UE->phy_sim_pdsch_rxdataF_ext) + buff_offset, numValidReSym, dec, op_format);
}
snprintf(fName, sizeof(fName), "chestF0_s%d.m", i);
LOG_M(fName, "chF0", ((c16_t *)UE->phy_sim_pdsch_dl_ch_estimates) + i * frame_parms->ofdm_symbol_size, nrb*12, dec, op_format);
}
}
}
LOG_M("chestF0.m", "chF0", UE->phy_sim_pdsch_dl_ch_estimates, frame_parms->ofdm_symbol_size * 14, dec, op_format);
@@ -1403,6 +1525,7 @@ printf("%d\n", slot);
free(UE->phy_sim_pdsch_dl_ch_estimates);
free(UE->phy_sim_pdsch_dl_ch_estimates_ext);
free(UE->phy_sim_dlsch_b);
free_and_zero(input_slot_iq);
free_nrLDPC_coding_interface(&gNB->nrLDPC_coding_interface);

View File

@@ -1384,7 +1384,7 @@ int main(int argc, char *argv[])
1 | log_format);
}
LOG_M("rxsigF0_llr.m",
LOG_M("rxF_llr.m",
"rxsF0_llr",
&pusch_vars->llr[0],
precod_nbr_layers * (nb_symb_sch - 1) * NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,

View File

@@ -126,7 +126,7 @@ static void set_tdd_config_nr_ue(fapi_nr_tdd_table_t *tdd_table, const frame_str
}
}
static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommonSIB_t *scc, int cc_idP)
void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommonSIB_t *scc, int cc_idP)
{
fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
mac->phy_config.Mod_id = mac->ue_id;
@@ -1553,7 +1553,7 @@ static void configure_dedicated_BWP_ul(NR_UE_MAC_INST_t *mac, int bwp_id, NR_BWP
}
}
static void configure_common_BWP_dl(NR_UE_MAC_INST_t *mac, int bwp_id, NR_BWP_DownlinkCommon_t *dl_common)
void configure_common_BWP_dl(NR_UE_MAC_INST_t *mac, int bwp_id, NR_BWP_DownlinkCommon_t *dl_common)
{
if (dl_common) {
NR_UE_DL_BWP_t *bwp = get_dl_bwp_structure(mac, bwp_id, true);

View File

@@ -409,4 +409,6 @@ void nr_ue_sidelink_scheduler(nr_sidelink_indication_t *sl_ind, NR_UE_MAC_INST_t
NR_SearchSpace_t *get_common_search_space(const NR_UE_MAC_INST_t *mac, const NR_SearchSpaceId_t ss_id);
void configure_common_BWP_dl(NR_UE_MAC_INST_t *mac, int bwp_id, NR_BWP_DownlinkCommon_t *dl_common);
void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommonSIB_t *scc, int cc_idP);
#endif

View File

@@ -0,0 +1,117 @@
#!/usr/bin/env python
# coding: utf-8
# In[42]:
import numpy as np
import matplotlib.pyplot as plt
import struct
import pandas as pd
# In[109]:
dataPath = '/home/sakthi/work/dlsim_perf/'
#csv_filename = 'iq_14_6_ueTimeDomainSamples_mcs26' + '.csv'
csv_filename = 'iq_197_6_ueTimeDomainSamples_mcs26_powerDrop1dB' + '.csv'
df = pd.read_csv(dataPath + csv_filename, sep=';')
dataR = df['real'].to_numpy().astype(np.int16)
dataI = df['imag'].to_numpy().astype(np.int16)
#shift = 2200
#dataR = np.roll(dataR, shift)
#dataI = np.roll(dataI, shift)
plt.plot(dataR)
print(dataI)
dataInter = np.zeros((2*dataR.size),dtype=np.int16)
dataInter[0::2] = dataR
dataInter[1::2] = dataI
print(dataInter)
# In[78]:
slotLen = 30720
numSlots = 10
slot = 6
dataFrame = np.zeros((numSlots * slotLen,2), dtype=np.int16)
dataFrame[slotLen*6:slotLen*6+slotLen,0] = dataR
dataFrame[slotLen*6:slotLen*6+slotLen,1] = dataI
write_file = 'wavejudge_input.txt'
np.savetxt(dataPath + write_file,dataFrame,delimiter=',', fmt='%d')
# In[80]:
# PDSCH config
import yaml
config_file = 'PDCCH_703-6_MCS22'
config_ext = '.txt'
with open(dataPath + config_file + config_ext, "r") as f:
content = f.read().replace('\t', ' ') # two spaces
with open(dataPath + config_file + 'space' + config_ext, "w") as f:
f.write(content)
print(content)
# In[107]:
cell_config = {
"dl_freq" : 1815000000,
"frame" : 643,
"slot" : 6,
"cellid" : 0,
"rnti" : 32768,
}
# In[100]:
write_file = 'dlsim_input_data.bin'
with open(dataPath + write_file, 'wb') as f:
for key,value in cell_config.items():
f.write(np.uint64(value).tobytes()) # write pdsch config
dataInter.tofile(f) # Write time domain samples
# In[110]:
# Create bin file with sib1, rrcsetup config and samples
sib_file = 'keysight_gnb_sib1.bin'
rrc_file = 'keysight_gnb_rrcsetup.bin'
write_file = 'dlsim_input_data.bin'
with open(dataPath + write_file, 'wb') as wf:
for key,value in cell_config.items():
wf.write(np.uint64(value).tobytes())
with open(dataPath + sib_file, 'rb') as f:
data = f.read()
wf.write(np.uint32(len(data)).tobytes())
wf.write(data)
with open(dataPath + rrc_file, 'rb') as f:
data = f.read()
wf.write(np.uint32(len(data)).tobytes())
wf.write(data)
wf.write(np.uint64(dataInter.size))
dataInter.tofile(wf)
# In[50]:
get_ipython().system('jupyter nbconvert --to script dlsim_ext_data.ipynb')
# In[ ]: