Commit d8a83c1e authored by brobert's avatar brobert

sending vars through unique structure

parent a1da6236
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <string.h>
......@@ -43,928 +43,962 @@
#define dBc(x,y) (dB_fixed(((int32_t)(x))*(x) + ((int32_t)(y))*(y)))
__attribute__((always_inline)) inline c16_t c32x16cumulVectVectWithSteps(c16_t *in1,
int *offset1,
const int step1,
c16_t *in2,
int *offset2,
const int step2,
const int modulo2,
const int N) {
int localOffset1=*offset1;
int localOffset2=*offset2;
c32_t cumul={0};
for (int i=0; i<N; i++) {
cumul=c32x16maddShift(in1[localOffset1], in2[localOffset2], cumul, 15);
localOffset1+=step1;
localOffset2= (localOffset2 + step2) % modulo2;
}
*offset1=localOffset1;
*offset2=localOffset2;
return c16x32div(cumul, N);
int *offset1,
const int step1,
c16_t *in2,
int *offset2,
const int step2,
const int modulo2,
const int N) {
int localOffset1=*offset1;
int localOffset2=*offset2;
c32_t cumul={0};
for (int i=0; i<N; i++) {
cumul=c32x16maddShift(in1[localOffset1], in2[localOffset2], cumul, 15);
localOffset1+=step1;
localOffset2= (localOffset2 + step2) % modulo2;
}
*offset1=localOffset1;
*offset2=localOffset2;
return c16x32div(cumul, N);
}
int inner_channel_estimation (
PHY_VARS_gNB *gNB
, int aarx
, const int symbol_offset
, c16_t **ul_ch_estimates
, int nl
, int ch_offset
, const int symbolSize
, nfapi_nr_pusch_pdu_t *pusch_pdu
, const int chest_freq
, c16_t pilot[3280] // __attribute__((aligned(32)))
, const int k0
, const int nb_rb_pusch
, unsigned short p
, const int soffset
, int *max_ch
, c16_t ul_ls_est[symbolSize]
, NR_gNB_PUSCH *pusch_vars
, delay_t *delay
, uint64_t noise_amp2
, int nest_count
, const int nushift
) {
c16_t *rxdataF = (c16_t *)&gNB->common_vars.rxdataF[aarx][symbol_offset];
c16_t *ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][ch_offset];
memset(ul_ch,0,sizeof(*ul_ch)*symbolSize);
#ifdef DEBUG_PUSCH
LOG_I(PHY, "In %s symbol_offset %d, nushift %d\n", __FUNCTION__, symbol_offset, nushift);
LOG_I(PHY, "In %s ch est pilot, N_RB_UL %d\n", __FUNCTION__, gNB->frame_parms.N_RB_UL);
LOG_I(PHY, "In %s bwp_start_subcarrier %d, k0 %d, first_carrier %d, nb_rb_pusch %d\n", __FUNCTION__, bwp_start_subcarrier, k0, gNB->frame_parms.first_carrier_offset, nb_rb_pusch);
LOG_I(PHY, "In %s ul_ch addr %p nushift %d\n", __FUNCTION__, ul_ch, nushift);
#endif
if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1 && chest_freq == 0) {
c16_t *pil = pilot;
int re_offset = k0;
LOG_D(PHY,"PUSCH estimation DMRS type 1, Freq-domain interpolation");
// For configuration type 1: k = 4*n + 2*k' + delta,
// where k' is 0 or 1, and delta is in Table 6.4.1.1.3-1 from TS 38.211
int pilot_cnt = 0;
int delta = nr_pusch_dmrs_delta(pusch_dmrs_type1, p);
for (int n = 0; n < 3 * nb_rb_pusch; n++) {
// LS estimation
c32_t ch = {0};
for (int k_line = 0; k_line <= 1; k_line++) {
re_offset = (k0 + (n << 2) + (k_line << 1) + delta) % symbolSize;
ch = c32x16maddShift(*pil, rxdataF[soffset + re_offset], ch, 16);
pil++;
}
c16_t ch16 = {.r = (int16_t)ch.r, .i = (int16_t)ch.i};
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) {
ul_ls_est[k] = ch16;
}
pilot_cnt += 2;
}
nr_est_delay(gNB->frame_parms.ofdm_symbol_size, ul_ls_est, (c16_t *)pusch_vars->ul_ch_estimates_time[aarx], delay);
int delay_idx = get_delay_idx(delay->est_delay, MAX_DELAY_COMP);
c16_t *ul_delay_table = gNB->frame_parms.delay_table[delay_idx];
#ifdef DEBUG_PUSCH
printf("Estimated delay = %i\n", delay->est_delay >> 1);
#endif
pilot_cnt = 0;
for (int n = 0; n < 3*nb_rb_pusch; n++) {
// Channel interpolation
for (int k_line = 0; k_line <= 1; k_line++) {
// Apply delay
int k = pilot_cnt << 1;
c16_t ch16 = c16mulShift(ul_ls_est[k], ul_delay_table[k], 8);
#ifdef DEBUG_PUSCH
re_offset = (k0 + (n << 2) + (k_line << 1)) % symbolSize;
c16_t *rxF = &rxdataF[soffset + re_offset];
printf("pilot %4d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d)\n",
pilot_cnt, pil->r, pil->i, rxF->r, rxF->i, ch.r, ch.i);
#endif
if (pilot_cnt == 0) {
c16multaddVectRealComplex(filt16_ul_p0, &ch16, ul_ch, 16);
} else if (pilot_cnt == 1 || pilot_cnt == 2) {
c16multaddVectRealComplex(filt16_ul_p1p2, &ch16, ul_ch, 16);
} else if (pilot_cnt == (6 * nb_rb_pusch - 1)) {
c16multaddVectRealComplex(filt16_ul_last, &ch16, ul_ch, 16);
} else {
c16multaddVectRealComplex(filt16_ul_middle, &ch16, ul_ch, 16);
if (pilot_cnt % 2 == 0) {
ul_ch += 4;
}
}
pilot_cnt++;
}
}
// Revert delay
pilot_cnt = 0;
ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][ch_offset];
int inv_delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP);
c16_t *ul_inv_delay_table = gNB->frame_parms.delay_table[inv_delay_idx];
for (int n = 0; n < 3 * nb_rb_pusch; n++) {
for (int k_line = 0; k_line <= 1; k_line++) {
int k = pilot_cnt << 1;
ul_ch[k] = c16mulShift(ul_ch[k], ul_inv_delay_table[k], 8);
ul_ch[k + 1] = c16mulShift(ul_ch[k + 1], ul_inv_delay_table[k + 1], 8);
noise_amp2 += c16amp2(c16sub(ul_ls_est[k], ul_ch[k]));
noise_amp2 += c16amp2(c16sub(ul_ls_est[k + 1], ul_ch[k + 1]));
#ifdef DEBUG_PUSCH
re_offset = (k0 + (n << 2) + (k_line << 1)) % symbolSize;
c16_t *rxF = &rxdataF[soffset + re_offset];
printf("ch -> (%4d,%4d), ch_inter -> (%4d,%4d)\n", ul_ls_est[k].r, ul_ls_est[k].i, ul_ch[k].r, ul_ch[k].i);
#endif
pilot_cnt++;
nest_count += 2;
}
}
} else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type2 && chest_freq == 0) { // pusch_dmrs_type2 |p_r,p_l,d,d,d,d,p_r,p_l,d,d,d,d|
LOG_D(PHY, "PUSCH estimation DMRS type 2, Freq-domain interpolation\n");
c16_t *pil = pilot;
c16_t *rx = &rxdataF[soffset + nushift];
for (int n = 0; n < nb_rb_pusch * NR_NB_SC_PER_RB; n += 6) {
c16_t ch0 = c16mulShift(*pil, rx[(k0 + n) % symbolSize], 15);
pil++;
c16_t ch1 = c16mulShift(*pil, rx[(k0 + n + 1) % symbolSize], 15);
pil++;
c16_t ch = c16addShift(ch0, ch1, 1);
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
multadd_real_four_symbols_vector_complex_scalar(filt8_rep4, &ch, &ul_ls_est[n]);
ul_ls_est[n + 4] = ch;
ul_ls_est[n + 5] = ch;
noise_amp2 += c16amp2(c16sub(ch0, ch));
nest_count++;
}
// Delay compensation
nr_est_delay(gNB->frame_parms.ofdm_symbol_size, ul_ls_est, (c16_t *)pusch_vars->ul_ch_estimates_time[aarx], delay);
int delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP);
c16_t *ul_delay_table = gNB->frame_parms.delay_table[delay_idx];
for (int n = 0; n < nb_rb_pusch * NR_NB_SC_PER_RB; n++) {
ul_ch[n] = c16mulShift(ul_ls_est[n], ul_delay_table[n % 6], 8);
}
}
else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1) { // this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 6 DMRS REs and use a common value for the whole PRB
LOG_D(PHY,"PUSCH estimation DMRS type 1, no Freq-domain interpolation\n");
c16_t *rxF = &rxdataF[soffset + nushift];
int pil_offset = 0;
int re_offset = k0;
c16_t ch;
// First PRB
ch=c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6);
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
c16multaddVectRealComplex(filt8_avlip0, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip1, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip2, &ch, ul_ch, 8);
ul_ch -= 12;
#endif
for (int pilot_cnt=6; pilot_cnt<6*(nb_rb_pusch-1); pilot_cnt += 6) {
ch=c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6);
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
ul_ch[3].r += (ch.r * 1365)>>15; // 1/12*16384
ul_ch[3].i += (ch.i * 1365)>>15; // 1/12*16384
ul_ch += 4;
c16multaddVectRealComplex(filt8_avlip3, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip4, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip5, &ch, ul_ch, 8);
ul_ch -= 8;
#endif
}
// Last PRB
ch=c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6);
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
ul_ch[3].r += (ch.r * 1365)>>15; // 1/12*16384
ul_ch[3].i += (ch.i * 1365)>>15; // 1/12*16384
ul_ch += 4;
c16multaddVectRealComplex(filt8_avlip3, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip6, &ch, ul_ch, 8);
#endif
} else { // this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 4 DMRS REs and use a common value for the whole PRB
LOG_D(PHY,"PUSCH estimation DMRS type 2, no Freq-domain interpolation");
c16_t *pil = pilot;
int re_offset = k0;
c32_t ch0={0};
//First PRB
ch0=c32x16mulShift(*pil,
rxdataF[soffset + nushift + re_offset],
15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil,
rxdataF[nushift+re_offset],
ch0,
15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch0=c32x16maddShift(*pil,
rxdataF[nushift+re_offset],
ch0,
15);
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil,
rxdataF[nushift+re_offset],
ch0,
15);
pil++;
re_offset = (re_offset+5) % symbolSize;
c16_t ch=c16x32div(ch0, 4);
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
c16multaddVectRealComplex(filt8_avlip0, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip1, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip2, &ch, ul_ch, 8);
ul_ch -= 12;
#endif
for (int pilot_cnt=4; pilot_cnt<4*(nb_rb_pusch-1); pilot_cnt += 4) {
c32_t ch0;
ch0=c32x16mulShift(*pil, rxdataF[nushift+re_offset], 15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch=c16x32div(ch0, 4);
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
ul_ch[3] = c16maddShift(ch, (c16_t){1365, 1365}, (c16_t){0, 0}, 15); // 1365 = 1/12*16384 (full range is +/- 32768)
ul_ch += 4;
c16multaddVectRealComplex(filt8_avlip3, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip4, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip5, &ch, ul_ch, 8);
ul_ch -= 8;
#endif
}
// Last PRB
ch0=c32x16mulShift(*pil, rxdataF[nushift+re_offset], 15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch=c16x32div(ch0, 4);
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
ul_ch[3] = c16maddShift(ch, (c16_t){1365, 1365}, (c16_t){0, 0}, 15); // 1365 = 1/12*16384 (full range is +/- 32768)
ul_ch += 4;
c16multaddVectRealComplex(filt8_avlip3, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip6, &ch, ul_ch, 8);
#endif
}
#ifdef DEBUG_PUSCH
ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][ch_offset];
for (int idxP = 0; idxP < ceil((float)nb_rb_pusch * 12 / 8); idxP++) {
for (int idxI = 0; idxI < 8; idxI++) {
printf("%d\t%d\t", ul_ch[idxP * 8 + idxI].r, ul_ch[idxP * 8 + idxI].i);
}
printf("%d\n", idxP);
}
#endif
return 0;
int inner_channel_estimation(inner_channel_estimation_params *rdata) {
PHY_VARS_gNB *gNB = rdata->gNB;
int aarx = rdata->aarx;
const int symbol_offset = rdata->symbol_offset;
c16_t **ul_ch_estimates = rdata->ul_ch_estimates;
int nl = rdata->nl;
int ch_offset = rdata->ch_offset;
const int symbolSize = rdata->symbolSize;
nfapi_nr_pusch_pdu_t *pusch_pdu = rdata->pusch_pdu;
const int chest_freq = rdata->chest_freq;
c16_t *pilot = rdata->pilot;
const int k0 = rdata->k0;
const int nb_rb_pusch = rdata->nb_rb_pusch;
unsigned short p = rdata->p;
const int soffset = rdata->soffset;
int *max_ch = rdata->max_ch;
c16_t *ul_ls_est = rdata->ul_ls_est;
NR_gNB_PUSCH *pusch_vars = rdata->pusch_vars;
delay_t *delay = rdata->delay;
uint64_t noise_amp2 = rdata->noise_amp2;
int nest_count = rdata->nest_count;
const int nushift = rdata->nushift;
c16_t *rxdataF = (c16_t *)&gNB->common_vars.rxdataF[aarx][symbol_offset];
c16_t *ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][ch_offset];
memset(ul_ch,0,sizeof(*ul_ch)*symbolSize);
#ifdef DEBUG_PUSCH
LOG_I(PHY, "In %s symbol_offset %d, nushift %d\n", __FUNCTION__, symbol_offset, nushift);
LOG_I(PHY, "In %s ch est pilot, N_RB_UL %d\n", __FUNCTION__, gNB->frame_parms.N_RB_UL);
LOG_I(PHY, "In %s bwp_start_subcarrier %d, k0 %d, first_carrier %d, nb_rb_pusch %d\n", __FUNCTION__, bwp_start_subcarrier, k0, gNB->frame_parms.first_carrier_offset, nb_rb_pusch);
LOG_I(PHY, "In %s ul_ch addr %p nushift %d\n", __FUNCTION__, ul_ch, nushift);
#endif
if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1 && chest_freq == 0) {
c16_t *pil = pilot;
int re_offset = k0;
LOG_D(PHY,"PUSCH estimation DMRS type 1, Freq-domain interpolation");
// For configuration type 1: k = 4*n + 2*k' + delta,
// where k' is 0 or 1, and delta is in Table 6.4.1.1.3-1 from TS 38.211
int pilot_cnt = 0;
int delta = nr_pusch_dmrs_delta(pusch_dmrs_type1, p);
for (int n = 0; n < 3 * nb_rb_pusch; n++) {
// LS estimation
c32_t ch = {0};
for (int k_line = 0; k_line <= 1; k_line++) {
re_offset = (k0 + (n << 2) + (k_line << 1) + delta) % symbolSize;
ch = c32x16maddShift(*pil, rxdataF[soffset + re_offset], ch, 16);
pil++;
}
c16_t ch16 = {.r = (int16_t)ch.r, .i = (int16_t)ch.i};
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) {
ul_ls_est[k] = ch16;
}
pilot_cnt += 2;
}
nr_est_delay(gNB->frame_parms.ofdm_symbol_size, ul_ls_est, (c16_t *)pusch_vars->ul_ch_estimates_time[aarx], delay);
int delay_idx = get_delay_idx(delay->est_delay, MAX_DELAY_COMP);
c16_t *ul_delay_table = gNB->frame_parms.delay_table[delay_idx];
#ifdef DEBUG_PUSCH
printf("Estimated delay = %i\n", delay->est_delay >> 1);
#endif
pilot_cnt = 0;
for (int n = 0; n < 3*nb_rb_pusch; n++) {
// Channel interpolation
for (int k_line = 0; k_line <= 1; k_line++) {
// Apply delay
int k = pilot_cnt << 1;
c16_t ch16 = c16mulShift(ul_ls_est[k], ul_delay_table[k], 8);
#ifdef DEBUG_PUSCH
re_offset = (k0 + (n << 2) + (k_line << 1)) % symbolSize;
c16_t *rxF = &rxdataF[soffset + re_offset];
printf("pilot %4d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d)\n",
pilot_cnt, pil->r, pil->i, rxF->r, rxF->i, ch.r, ch.i);
#endif
if (pilot_cnt == 0) {
c16multaddVectRealComplex(filt16_ul_p0, &ch16, ul_ch, 16);
} else if (pilot_cnt == 1 || pilot_cnt == 2) {
c16multaddVectRealComplex(filt16_ul_p1p2, &ch16, ul_ch, 16);
} else if (pilot_cnt == (6 * nb_rb_pusch - 1)) {
c16multaddVectRealComplex(filt16_ul_last, &ch16, ul_ch, 16);
} else {
c16multaddVectRealComplex(filt16_ul_middle, &ch16, ul_ch, 16);
if (pilot_cnt % 2 == 0) {
ul_ch += 4;
}
}
pilot_cnt++;
}
}
// Revert delay
pilot_cnt = 0;
ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][ch_offset];
int inv_delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP);
c16_t *ul_inv_delay_table = gNB->frame_parms.delay_table[inv_delay_idx];
for (int n = 0; n < 3 * nb_rb_pusch; n++) {
for (int k_line = 0; k_line <= 1; k_line++) {
int k = pilot_cnt << 1;
ul_ch[k] = c16mulShift(ul_ch[k], ul_inv_delay_table[k], 8);
ul_ch[k + 1] = c16mulShift(ul_ch[k + 1], ul_inv_delay_table[k + 1], 8);
noise_amp2 += c16amp2(c16sub(ul_ls_est[k], ul_ch[k]));
noise_amp2 += c16amp2(c16sub(ul_ls_est[k + 1], ul_ch[k + 1]));
#ifdef DEBUG_PUSCH
re_offset = (k0 + (n << 2) + (k_line << 1)) % symbolSize;
c16_t *rxF = &rxdataF[soffset + re_offset];
printf("ch -> (%4d,%4d), ch_inter -> (%4d,%4d)\n", ul_ls_est[k].r, ul_ls_est[k].i, ul_ch[k].r, ul_ch[k].i);
#endif
pilot_cnt++;
nest_count += 2;
}
}
} else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type2 && chest_freq == 0) { // pusch_dmrs_type2 |p_r,p_l,d,d,d,d,p_r,p_l,d,d,d,d|
LOG_D(PHY, "PUSCH estimation DMRS type 2, Freq-domain interpolation\n");
c16_t *pil = pilot;
c16_t *rx = &rxdataF[soffset + nushift];
for (int n = 0; n < nb_rb_pusch * NR_NB_SC_PER_RB; n += 6) {
c16_t ch0 = c16mulShift(*pil, rx[(k0 + n) % symbolSize], 15);
pil++;
c16_t ch1 = c16mulShift(*pil, rx[(k0 + n + 1) % symbolSize], 15);
pil++;
c16_t ch = c16addShift(ch0, ch1, 1);
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
multadd_real_four_symbols_vector_complex_scalar(filt8_rep4, &ch, &ul_ls_est[n]);
ul_ls_est[n + 4] = ch;
ul_ls_est[n + 5] = ch;
noise_amp2 += c16amp2(c16sub(ch0, ch));
nest_count++;
}
// Delay compensation
nr_est_delay(gNB->frame_parms.ofdm_symbol_size, ul_ls_est, (c16_t *)pusch_vars->ul_ch_estimates_time[aarx], delay);
int delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP);
c16_t *ul_delay_table = gNB->frame_parms.delay_table[delay_idx];
for (int n = 0; n < nb_rb_pusch * NR_NB_SC_PER_RB; n++) {
ul_ch[n] = c16mulShift(ul_ls_est[n], ul_delay_table[n % 6], 8);
}
}
else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1) { // this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 6 DMRS REs and use a common value for the whole PRB
LOG_D(PHY,"PUSCH estimation DMRS type 1, no Freq-domain interpolation\n");
c16_t *rxF = &rxdataF[soffset + nushift];
int pil_offset = 0;
int re_offset = k0;
c16_t ch;
// First PRB
ch=c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6);
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
c16multaddVectRealComplex(filt8_avlip0, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip1, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip2, &ch, ul_ch, 8);
ul_ch -= 12;
#endif
for (int pilot_cnt=6; pilot_cnt<6*(nb_rb_pusch-1); pilot_cnt += 6) {
ch=c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6);
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
ul_ch[3].r += (ch.r * 1365)>>15; // 1/12*16384
ul_ch[3].i += (ch.i * 1365)>>15; // 1/12*16384
ul_ch += 4;
c16multaddVectRealComplex(filt8_avlip3, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip4, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip5, &ch, ul_ch, 8);
ul_ch -= 8;
#endif
}
// Last PRB
ch=c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6);
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
ul_ch[3].r += (ch.r * 1365)>>15; // 1/12*16384
ul_ch[3].i += (ch.i * 1365)>>15; // 1/12*16384
ul_ch += 4;
c16multaddVectRealComplex(filt8_avlip3, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip6, &ch, ul_ch, 8);
#endif
} else { // this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 4 DMRS REs and use a common value for the whole PRB
LOG_D(PHY,"PUSCH estimation DMRS type 2, no Freq-domain interpolation");
c16_t *pil = pilot;
int re_offset = k0;
c32_t ch0={0};
//First PRB
ch0=c32x16mulShift(*pil,
rxdataF[soffset + nushift + re_offset],
15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil,
rxdataF[nushift+re_offset],
ch0,
15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch0=c32x16maddShift(*pil,
rxdataF[nushift+re_offset],
ch0,
15);
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil,
rxdataF[nushift+re_offset],
ch0,
15);
pil++;
re_offset = (re_offset+5) % symbolSize;
c16_t ch=c16x32div(ch0, 4);
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
c16multaddVectRealComplex(filt8_avlip0, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip1, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip2, &ch, ul_ch, 8);
ul_ch -= 12;
#endif
for (int pilot_cnt=4; pilot_cnt<4*(nb_rb_pusch-1); pilot_cnt += 4) {
c32_t ch0;
ch0=c32x16mulShift(*pil, rxdataF[nushift+re_offset], 15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch=c16x32div(ch0, 4);
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
ul_ch[3] = c16maddShift(ch, (c16_t){1365, 1365}, (c16_t){0, 0}, 15); // 1365 = 1/12*16384 (full range is +/- 32768)
ul_ch += 4;
c16multaddVectRealComplex(filt8_avlip3, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip4, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip5, &ch, ul_ch, 8);
ul_ch -= 8;
#endif
}
// Last PRB
ch0=c32x16mulShift(*pil, rxdataF[nushift+re_offset], 15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch=c16x32div(ch0, 4);
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
ul_ch[3] = c16maddShift(ch, (c16_t){1365, 1365}, (c16_t){0, 0}, 15); // 1365 = 1/12*16384 (full range is +/- 32768)
ul_ch += 4;
c16multaddVectRealComplex(filt8_avlip3, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip6, &ch, ul_ch, 8);
#endif
}
#ifdef DEBUG_PUSCH
ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][ch_offset];
for (int idxP = 0; idxP < ceil((float)nb_rb_pusch * 12 / 8); idxP++) {
for (int idxI = 0; idxI < 8; idxI++) {
printf("%d\t%d\t", ul_ch[idxP * 8 + idxI].r, ul_ch[idxP * 8 + idxI].i);
}
printf("%d\n", idxP);
}
#endif
// value update of rdata to be passed to the next inner call
rdata->max_ch = max_ch; // Placeholder for max channel value update
rdata->noise_amp2 = noise_amp2; // Placeholder for noise amplitude squared update
delay->est_delay = rdata->delay->est_delay; // Placeholder for estimated delay update
nest_count = rdata->nest_count; // Placeholder for nested count update
rdata->ul_ls_est = ul_ls_est; // Placeholder for uplink least square estimation
return 0;
}
int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
unsigned char Ns,
int nl,
unsigned short p,
unsigned char symbol,
int ul_id,
unsigned short bwp_start_subcarrier,
nfapi_nr_pusch_pdu_t *pusch_pdu,
int *max_ch,
uint32_t *nvar)
unsigned char Ns,
int nl,
unsigned short p,
unsigned char symbol,
int ul_id,
unsigned short bwp_start_subcarrier,
nfapi_nr_pusch_pdu_t *pusch_pdu,
int *max_ch,
uint32_t *nvar)
{
c16_t pilot[3280] __attribute__((aligned(32)));
const int chest_freq = gNB->chest_freq;
c16_t pilot[3280] __attribute__((aligned(32)));
const int chest_freq = gNB->chest_freq;
#ifdef DEBUG_CH
FILE *debug_ch_est;
debug_ch_est = fopen("debug_ch_est.txt","w");
FILE *debug_ch_est;
debug_ch_est = fopen("debug_ch_est.txt","w");
#endif
NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ul_id];
c16_t **ul_ch_estimates = (c16_t **)pusch_vars->ul_ch_estimates;
const int symbolSize = gNB->frame_parms.ofdm_symbol_size;
const int soffset = (Ns & 3) * gNB->frame_parms.symbols_per_slot*symbolSize;
const int nushift = (p >> 1) & 1;
int ch_offset = symbolSize*symbol;
const int symbol_offset = symbolSize*symbol;
const int k0 = bwp_start_subcarrier;
const int nb_rb_pusch = pusch_pdu->rb_size;
LOG_D(PHY, "ch_offset %d, soffset %d, symbol_offset %d, OFDM size %d, Ns = %d, k0 = %d, symbol %d\n",
ch_offset, soffset,
symbol_offset,
symbolSize,
Ns,
k0,
symbol);
//------------------generate DMRS------------------//
if(pusch_pdu->ul_dmrs_scrambling_id != gNB->pusch_gold_init[pusch_pdu->scid]) {
gNB->pusch_gold_init[pusch_pdu->scid] = pusch_pdu->ul_dmrs_scrambling_id;
nr_gold_pusch(gNB, pusch_pdu->scid, pusch_pdu->ul_dmrs_scrambling_id);
}
if (pusch_pdu->transform_precoding == transformPrecoder_disabled) {
// Note: pilot returned by the following function is already the complex conjugate of the transmitted DMRS
nr_pusch_dmrs_rx(gNB,
Ns,
gNB->nr_gold_pusch_dmrs[pusch_pdu->scid][Ns][symbol],
pilot,
(1000 + p),
0,
nb_rb_pusch,
(pusch_pdu->bwp_start + pusch_pdu->rb_start) * NR_NB_SC_PER_RB,
pusch_pdu->dmrs_config_type);
} else { // if transform precoding or SC-FDMA is enabled in Uplink
// NR_SC_FDMA supports type1 DMRS so only 6 DMRS REs per RB possible
const int index = get_index_for_dmrs_lowpapr_seq(nb_rb_pusch * (NR_NB_SC_PER_RB / 2));
const uint8_t u = pusch_pdu->dfts_ofdm.low_papr_group_number;
const uint8_t v = pusch_pdu->dfts_ofdm.low_papr_sequence_number;
c16_t *dmrs_seq = gNB_dmrs_lowpaprtype1_sequence[u][v][index];
LOG_D(PHY,"Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index);
AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n");
AssertFatal(dmrs_seq != NULL, "DMRS low PAPR seq not found, check if DMRS sequences are generated");
nr_pusch_lowpaprtype1_dmrs_rx(gNB, Ns, dmrs_seq, pilot, 1000, 0, nb_rb_pusch, 0, pusch_pdu->dmrs_config_type);
NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ul_id];
c16_t **ul_ch_estimates = (c16_t **)pusch_vars->ul_ch_estimates;
const int symbolSize = gNB->frame_parms.ofdm_symbol_size;
const int soffset = (Ns & 3) * gNB->frame_parms.symbols_per_slot*symbolSize;
const int nushift = (p >> 1) & 1;
int ch_offset = symbolSize*symbol;
const int symbol_offset = symbolSize*symbol;
const int k0 = bwp_start_subcarrier;
const int nb_rb_pusch = pusch_pdu->rb_size;
LOG_D(PHY, "ch_offset %d, soffset %d, symbol_offset %d, OFDM size %d, Ns = %d, k0 = %d, symbol %d\n",
ch_offset, soffset,
symbol_offset,
symbolSize,
Ns,
k0,
symbol);
//------------------generate DMRS------------------//
if(pusch_pdu->ul_dmrs_scrambling_id != gNB->pusch_gold_init[pusch_pdu->scid]) {
gNB->pusch_gold_init[pusch_pdu->scid] = pusch_pdu->ul_dmrs_scrambling_id;
nr_gold_pusch(gNB, pusch_pdu->scid, pusch_pdu->ul_dmrs_scrambling_id);
}
if (pusch_pdu->transform_precoding == transformPrecoder_disabled) {
// Note: pilot returned by the following function is already the complex conjugate of the transmitted DMRS
nr_pusch_dmrs_rx(gNB,
Ns,
gNB->nr_gold_pusch_dmrs[pusch_pdu->scid][Ns][symbol],
pilot,
(1000 + p),
0,
nb_rb_pusch,
(pusch_pdu->bwp_start + pusch_pdu->rb_start) * NR_NB_SC_PER_RB,
pusch_pdu->dmrs_config_type);
} else { // if transform precoding or SC-FDMA is enabled in Uplink
// NR_SC_FDMA supports type1 DMRS so only 6 DMRS REs per RB possible
const int index = get_index_for_dmrs_lowpapr_seq(nb_rb_pusch * (NR_NB_SC_PER_RB / 2));
const uint8_t u = pusch_pdu->dfts_ofdm.low_papr_group_number;
const uint8_t v = pusch_pdu->dfts_ofdm.low_papr_sequence_number;
c16_t *dmrs_seq = gNB_dmrs_lowpaprtype1_sequence[u][v][index];
LOG_D(PHY,"Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index);
AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n");
AssertFatal(dmrs_seq != NULL, "DMRS low PAPR seq not found, check if DMRS sequences are generated");
nr_pusch_lowpaprtype1_dmrs_rx(gNB, Ns, dmrs_seq, pilot, 1000, 0, nb_rb_pusch, 0, pusch_pdu->dmrs_config_type);
#ifdef DEBUG_PUSCH
printf ("NR_UL_CHANNEL_EST: index %d, u %d,v %d\n", index, u, v);
LOG_M("gNb_DMRS_SEQ.m","gNb_DMRS_SEQ", dmrs_seq,6*nb_rb_pusch,1,1);
printf ("NR_UL_CHANNEL_EST: index %d, u %d,v %d\n", index, u, v);
LOG_M("gNb_DMRS_SEQ.m","gNb_DMRS_SEQ", dmrs_seq,6*nb_rb_pusch,1,1);
#endif
}
//------------------------------------------------//
}
//------------------------------------------------//
#ifdef DEBUG_PUSCH
for (int i = 0; i < (6 * nb_rb_pusch); i++) {
LOG_I(PHY, "In %s: %d + j*(%d)\n", __FUNCTION__, pilot[i].r,pilot[i].i);
}
for (int i = 0; i < (6 * nb_rb_pusch); i++) {
LOG_I(PHY, "In %s: %d + j*(%d)\n", __FUNCTION__, pilot[i].r,pilot[i].i);
}
#endif
int nest_count = 0;
uint64_t noise_amp2 = 0;
c16_t ul_ls_est[symbolSize] __attribute__((aligned(32)));
memset(ul_ls_est, 0, sizeof(c16_t) * symbolSize);
delay_t *delay = &gNB->ulsch[ul_id].delay;
memset(delay, 0, sizeof(*delay));
for (int aarx=0; aarx<gNB->frame_parms.nb_antennas_rx; aarx++) {
inner_channel_estimation (
gNB
, aarx
, symbol_offset
, ul_ch_estimates
, nl
, ch_offset
, symbolSize
, pusch_pdu
, chest_freq
, pilot
, k0
, nb_rb_pusch
, p
, soffset
, max_ch
, ul_ls_est
, pusch_vars
, delay
, noise_amp2
, nest_count
, nushift
);
}
int nest_count = 0;
uint64_t noise_amp2 = 0;
c16_t ul_ls_est[symbolSize] __attribute__((aligned(32)));
memset(ul_ls_est, 0, sizeof(c16_t) * symbolSize);
delay_t *delay = &gNB->ulsch[ul_id].delay;
memset(delay, 0, sizeof(*delay));
//Initializing the structure before going through the loop
puschAntennaProc_t *rdata = (puschAntennaProc_t *)malloc(
sizeof(puschAntennaProc_t) + symbolSize * sizeof(c16_t)
);
if (!rdata) {
perror("Failed to allocate memory");
return -1;
}
for (int aarx=0; aarx<gNB->frame_parms.nb_antennas_rx; aarx++) {
// Local init in the current loop
rdata->aarx = aarx;
rdata->nest_count = nest_count;
rdata->noise_amp2 = noise_amp2;
rdata->ul_ls_est = ul_ls_est;
rdata->delay = delay;
rdata->gNB = gNB;
rdata->nb_antennas_rx = gNB->frame_parms.nb_antennas_rx
rdata->symbol_offset = symbol_offset;
rtada->ul_ch_estimates = ul_ch_estimates;
rdata->nl = nl;
rdata->ch_offset = ch_offset;
rdata->symbolSize = symbolSize;
rdata->pusch_pdu = pusch_pdu;
rdata->chest_freq = chest_freq;
rdata->pilot = pilot;
rdata->k0 = k0;
rdata->nb_rb_pusch = nb_rb_pusch;
rdata->p = p;
rdata->soffset = soffset;
rdata->max_ch = max_ch;
rdata->pusch_vars = pusch_vars;
rdata->nushift = nushift;
// Call the inner_channel_estimation function
int result = inner_channel_estimation(rdata);
// value update of rdata to be passed to the next inner call
max_ch = rdata->max_ch; // Placeholder for max channel value update
noise_amp2 = rdata->noise_amp2; // Placeholder for noise amplitude squared update
delay->est_delay = rdata->delay->est_delay; // Placeholder for estimated delay update
nest_count = rdata->nest_count; // Placeholder for nested count update
ul_ls_est = rdata->ul_ls_est;
}
// Free the allocated memory
free(rdata);
#ifdef DEBUG_CH
fclose(debug_ch_est);
fclose(debug_ch_est);
#endif
if (nvar && nest_count > 0) {
*nvar = (uint32_t)(noise_amp2 / nest_count);
}
if (nvar && nest_count > 0) {
*nvar = (uint32_t)(noise_amp2 / nest_count);
}
return 0;
return 0;
}
/*******************************************************************
*
* NAME : nr_pusch_ptrs_processing
*
* PARAMETERS : gNB : gNB data structure
* rel15_ul : UL parameters
* UE_id : UE ID
* nr_tti_rx : slot rx TTI
* dmrs_symbol_flag: DMRS Symbol Flag
* symbol : OFDM Symbol
* nb_re_pusch : PUSCH RE's
* nb_re_pusch : PUSCH RE's
*
* RETURN : nothing
*
* DESCRIPTION :
* If ptrs is enabled process the symbol accordingly
* 1) Estimate phase noise per PTRS symbol
* 2) Interpolate PTRS estimated value in TD after all PTRS symbols
* 3) Compensated DMRS based estimated signal with PTRS estimation for slot
*********************************************************************/
*
* NAME : nr_pusch_ptrs_processing
*
* PARAMETERS : gNB : gNB data structure
* rel15_ul : UL parameters
* UE_id : UE ID
* nr_tti_rx : slot rx TTI
* dmrs_symbol_flag: DMRS Symbol Flag
* symbol : OFDM Symbol
* nb_re_pusch : PUSCH RE's
* nb_re_pusch : PUSCH RE's
*
* RETURN : nothing
*
* DESCRIPTION :
* If ptrs is enabled process the symbol accordingly
* 1) Estimate phase noise per PTRS symbol
* 2) Interpolate PTRS estimated value in TD after all PTRS symbols
* 3) Compensated DMRS based estimated signal with PTRS estimation for slot
*********************************************************************/
// #define DEBUG_UL_PTRS
void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB,
NR_DL_FRAME_PARMS *frame_parms,
nfapi_nr_pusch_pdu_t *rel15_ul,
uint8_t ulsch_id,
uint8_t nr_tti_rx,
unsigned char symbol,
uint32_t nb_re_pusch)
NR_DL_FRAME_PARMS *frame_parms,
nfapi_nr_pusch_pdu_t *rel15_ul,
uint8_t ulsch_id,
uint8_t nr_tti_rx,
unsigned char symbol,
uint32_t nb_re_pusch)
{
NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ulsch_id];
int32_t *ptrs_re_symbol = NULL;
int8_t ret = 0;
uint8_t symbInSlot = rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols;
uint8_t *startSymbIndex = &rel15_ul->start_symbol_index;
uint8_t *nbSymb = &rel15_ul->nr_of_symbols;
uint8_t *L_ptrs = &rel15_ul->pusch_ptrs.ptrs_time_density;
uint8_t *K_ptrs = &rel15_ul->pusch_ptrs.ptrs_freq_density;
uint16_t *dmrsSymbPos = &rel15_ul->ul_dmrs_symb_pos;
uint16_t *ptrsSymbPos = &pusch_vars->ptrs_symbols;
uint8_t *ptrsSymbIdx = &pusch_vars->ptrs_symbol_index;
uint16_t *nb_rb = &rel15_ul->rb_size;
uint8_t *ptrsReOffset = &rel15_ul->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset;
/* loop over antennas */
for (int aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
c16_t *phase_per_symbol = (c16_t *)pusch_vars->ptrs_phase_per_slot[aarx];
ptrs_re_symbol = &pusch_vars->ptrs_re_per_slot;
*ptrs_re_symbol = 0;
phase_per_symbol[symbol].i = 0;
/* set DMRS estimates to 0 angle with magnitude 1 */
if(is_dmrs_symbol(symbol,*dmrsSymbPos)) {
/* set DMRS real estimation to 32767 */
phase_per_symbol[symbol].r=INT16_MAX; // 32767
NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ulsch_id];
int32_t *ptrs_re_symbol = NULL;
int8_t ret = 0;
uint8_t symbInSlot = rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols;
uint8_t *startSymbIndex = &rel15_ul->start_symbol_index;
uint8_t *nbSymb = &rel15_ul->nr_of_symbols;
uint8_t *L_ptrs = &rel15_ul->pusch_ptrs.ptrs_time_density;
uint8_t *K_ptrs = &rel15_ul->pusch_ptrs.ptrs_freq_density;
uint16_t *dmrsSymbPos = &rel15_ul->ul_dmrs_symb_pos;
uint16_t *ptrsSymbPos = &pusch_vars->ptrs_symbols;
uint8_t *ptrsSymbIdx = &pusch_vars->ptrs_symbol_index;
uint16_t *nb_rb = &rel15_ul->rb_size;
uint8_t *ptrsReOffset = &rel15_ul->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset;
/* loop over antennas */
for (int aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
c16_t *phase_per_symbol = (c16_t *)pusch_vars->ptrs_phase_per_slot[aarx];
ptrs_re_symbol = &pusch_vars->ptrs_re_per_slot;
*ptrs_re_symbol = 0;
phase_per_symbol[symbol].i = 0;
/* set DMRS estimates to 0 angle with magnitude 1 */
if(is_dmrs_symbol(symbol,*dmrsSymbPos)) {
/* set DMRS real estimation to 32767 */
phase_per_symbol[symbol].r=INT16_MAX; // 32767
#ifdef DEBUG_UL_PTRS
printf("[PHY][PTRS]: DMRS Symbol %d -> %4d + j*%4d\n", symbol, phase_per_symbol[symbol].r,phase_per_symbol[symbol].i);
printf("[PHY][PTRS]: DMRS Symbol %d -> %4d + j*%4d\n", symbol, phase_per_symbol[symbol].r,phase_per_symbol[symbol].i);
#endif
}
else {// real ptrs value is set to 0
phase_per_symbol[symbol].r = 0;
}
if(symbol == *startSymbIndex) {
*ptrsSymbPos = 0;
set_ptrs_symb_idx(ptrsSymbPos,
*nbSymb,
*startSymbIndex,
1<< *L_ptrs,
*dmrsSymbPos);
}
/* if not PTRS symbol set current ptrs symbol index to zero*/
*ptrsSymbIdx = 0;
/* Check if current symbol contains PTRS */
if(is_ptrs_symbol(symbol, *ptrsSymbPos)) {
*ptrsSymbIdx = symbol;
/*------------------------------------------------------------------------------------------------------- */
/* 1) Estimate common phase error per PTRS symbol */
/*------------------------------------------------------------------------------------------------------- */
nr_ptrs_cpe_estimation(*K_ptrs,
*ptrsReOffset,
*nb_rb,
rel15_ul->rnti,
nr_tti_rx,
symbol,
frame_parms->ofdm_symbol_size,
(int16_t *)&pusch_vars->rxdataF_comp[aarx][(symbol * nb_re_pusch)],
gNB->nr_gold_pusch_dmrs[rel15_ul->scid][nr_tti_rx][symbol],
(int16_t *)&phase_per_symbol[symbol],
ptrs_re_symbol);
}
/* For last OFDM symbol at each antenna perform interpolation and compensation for the slot*/
if(symbol == (symbInSlot -1)) {
/*------------------------------------------------------------------------------------------------------- */
/* 2) Interpolate PTRS estimated value in TD */
/*------------------------------------------------------------------------------------------------------- */
/* If L-PTRS is > 0 then we need interpolation */
if(*L_ptrs > 0) {
ret = nr_ptrs_process_slot(*dmrsSymbPos, *ptrsSymbPos, (int16_t*)phase_per_symbol, *startSymbIndex, *nbSymb);
if(ret != 0) {
LOG_W(PHY,"[PTRS] Compensation is skipped due to error in PTRS slot processing !!\n");
}
}
/*------------------------------------------------------------------------------------------------------- */
/* 3) Compensated DMRS based estimated signal with PTRS estimation */
/*--------------------------------------------------------------------------------------------------------*/
for(uint8_t i = *startSymbIndex; i < symbInSlot; i++) {
/* DMRS Symbol has 0 phase so no need to rotate the respective symbol */
/* Skip rotation if the slot processing is wrong */
if((!is_dmrs_symbol(i,*dmrsSymbPos)) && (ret == 0)) {
}
else {// real ptrs value is set to 0
phase_per_symbol[symbol].r = 0;
}
if(symbol == *startSymbIndex) {
*ptrsSymbPos = 0;
set_ptrs_symb_idx(ptrsSymbPos,
*nbSymb,
*startSymbIndex,
1<< *L_ptrs,
*dmrsSymbPos);
}
/* if not PTRS symbol set current ptrs symbol index to zero*/
*ptrsSymbIdx = 0;
/* Check if current symbol contains PTRS */
if(is_ptrs_symbol(symbol, *ptrsSymbPos)) {
*ptrsSymbIdx = symbol;
/*------------------------------------------------------------------------------------------------------- */
/* 1) Estimate common phase error per PTRS symbol */
/*------------------------------------------------------------------------------------------------------- */
nr_ptrs_cpe_estimation(*K_ptrs,
*ptrsReOffset,
*nb_rb,
rel15_ul->rnti,
nr_tti_rx,
symbol,
frame_parms->ofdm_symbol_size,
(int16_t *)&pusch_vars->rxdataF_comp[aarx][(symbol * nb_re_pusch)],
gNB->nr_gold_pusch_dmrs[rel15_ul->scid][nr_tti_rx][symbol],
(int16_t *)&phase_per_symbol[symbol],
ptrs_re_symbol);
}
/* For last OFDM symbol at each antenna perform interpolation and compensation for the slot*/
if(symbol == (symbInSlot -1)) {
/*------------------------------------------------------------------------------------------------------- */
/* 2) Interpolate PTRS estimated value in TD */
/*------------------------------------------------------------------------------------------------------- */
/* If L-PTRS is > 0 then we need interpolation */
if(*L_ptrs > 0) {
ret = nr_ptrs_process_slot(*dmrsSymbPos, *ptrsSymbPos, (int16_t*)phase_per_symbol, *startSymbIndex, *nbSymb);
if(ret != 0) {
LOG_W(PHY,"[PTRS] Compensation is skipped due to error in PTRS slot processing !!\n");
}
}
/*------------------------------------------------------------------------------------------------------- */
/* 3) Compensated DMRS based estimated signal with PTRS estimation */
/*--------------------------------------------------------------------------------------------------------*/
for(uint8_t i = *startSymbIndex; i < symbInSlot; i++) {
/* DMRS Symbol has 0 phase so no need to rotate the respective symbol */
/* Skip rotation if the slot processing is wrong */
if((!is_dmrs_symbol(i,*dmrsSymbPos)) && (ret == 0)) {
#ifdef DEBUG_UL_PTRS
printf("[PHY][UL][PTRS]: Rotate Symbol %2d with %d + j* %d\n", i, phase_per_symbol[i].r,phase_per_symbol[i].i);
printf("[PHY][UL][PTRS]: Rotate Symbol %2d with %d + j* %d\n", i, phase_per_symbol[i].r,phase_per_symbol[i].i);
#endif
rotate_cpx_vector((c16_t *)&pusch_vars->rxdataF_comp[aarx][i * nb_re_pusch],
&phase_per_symbol[i],
(c16_t *)&pusch_vars->rxdataF_comp[aarx][i * nb_re_pusch],
((*nb_rb) * NR_NB_SC_PER_RB),
15);
} // if not DMRS Symbol
} // symbol loop
} // last symbol check
} // Antenna loop
rotate_cpx_vector((c16_t *)&pusch_vars->rxdataF_comp[aarx][i * nb_re_pusch],
&phase_per_symbol[i],
(c16_t *)&pusch_vars->rxdataF_comp[aarx][i * nb_re_pusch],
((*nb_rb) * NR_NB_SC_PER_RB),
15);
} // if not DMRS Symbol
} // symbol loop
} // last symbol check
} // Antenna loop
}
uint32_t calc_power(const int16_t *x, const uint32_t size) {
int64_t sum_x = 0;
int64_t sum_x2 = 0;
for(int k = 0; k<size; k++) {
sum_x = sum_x + x[k];
sum_x2 = sum_x2 + x[k]*x[k];
}
return sum_x2/size - (sum_x/size)*(sum_x/size);
int64_t sum_x = 0;
int64_t sum_x2 = 0;
for(int k = 0; k<size; k++) {
sum_x = sum_x + x[k];
sum_x2 = sum_x2 + x[k]*x[k];
}
return sum_x2/size - (sum_x/size)*(sum_x/size);
}
int nr_srs_channel_estimation(
const PHY_VARS_gNB *gNB,
const int frame,
const int slot,
const nfapi_nr_srs_pdu_t *srs_pdu,
const nr_srs_info_t *nr_srs_info,
const c16_t **srs_generated_signal,
int32_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)],
int32_t srs_estimated_channel_freq[][1 << srs_pdu->num_ant_ports]
[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)],
int32_t srs_estimated_channel_time[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size],
int32_t srs_estimated_channel_time_shifted[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size],
int8_t *snr_per_rb,
int8_t *snr)
const PHY_VARS_gNB *gNB,
const int frame,
const int slot,
const nfapi_nr_srs_pdu_t *srs_pdu,
const nr_srs_info_t *nr_srs_info,
const c16_t **srs_generated_signal,
int32_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)],
int32_t srs_estimated_channel_freq[][1 << srs_pdu->num_ant_ports]
[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)],
int32_t srs_estimated_channel_time[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size],
int32_t srs_estimated_channel_time_shifted[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size],
int8_t *snr_per_rb,
int8_t *snr)
{
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"Calling %s function\n", __FUNCTION__);
LOG_I(NR_PHY,"Calling %s function\n", __FUNCTION__);
#endif
const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start*NR_NB_SC_PER_RB;
const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start*NR_NB_SC_PER_RB;
const uint8_t N_ap = 1<<srs_pdu->num_ant_ports;
const uint8_t K_TC = 2<<srs_pdu->comb_size;
const uint16_t m_SRS_b = srs_bandwidth_config[srs_pdu->config_index][srs_pdu->bandwidth_index][0];
const uint16_t M_sc_b_SRS = m_SRS_b * NR_NB_SC_PER_RB/K_TC;
uint8_t fd_cdm = N_ap;
if (N_ap == 4 && ((K_TC == 2 && srs_pdu->cyclic_shift >= 4) || (K_TC == 4 && srs_pdu->cyclic_shift >= 6))) {
fd_cdm = 2;
}
c16_t srs_ls_estimated_channel[frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols)];
uint32_t noise_power_per_rb[srs_pdu->bwp_size];
const uint32_t arr_len = frame_parms->nb_antennas_rx * N_ap * M_sc_b_SRS;
const uint8_t N_ap = 1<<srs_pdu->num_ant_ports;
const uint8_t K_TC = 2<<srs_pdu->comb_size;
const uint16_t m_SRS_b = srs_bandwidth_config[srs_pdu->config_index][srs_pdu->bandwidth_index][0];
const uint16_t M_sc_b_SRS = m_SRS_b * NR_NB_SC_PER_RB/K_TC;
uint8_t fd_cdm = N_ap;
if (N_ap == 4 && ((K_TC == 2 && srs_pdu->cyclic_shift >= 4) || (K_TC == 4 && srs_pdu->cyclic_shift >= 6))) {
fd_cdm = 2;
}
int16_t ch_real[arr_len];
memset(ch_real, 0, arr_len * sizeof(int16_t));
c16_t srs_ls_estimated_channel[frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols)];
uint32_t noise_power_per_rb[srs_pdu->bwp_size];
int16_t ch_imag[arr_len];
memset(ch_imag, 0, arr_len * sizeof(int16_t));
const uint32_t arr_len = frame_parms->nb_antennas_rx * N_ap * M_sc_b_SRS;
int16_t noise_real[arr_len];
memset(noise_real, 0, arr_len * sizeof(int16_t));
int16_t ch_real[arr_len];
memset(ch_real, 0, arr_len * sizeof(int16_t));
int16_t ch_imag[arr_len];
memset(ch_imag, 0, arr_len * sizeof(int16_t));
int16_t noise_real[arr_len];
memset(noise_real, 0, arr_len * sizeof(int16_t));
int16_t noise_imag[arr_len];
memset(noise_imag, 0, arr_len * sizeof(int16_t));
int16_t noise_imag[arr_len];
memset(noise_imag, 0, arr_len * sizeof(int16_t));
int16_t ls_estimated[2];
int16_t ls_estimated[2];
uint8_t mem_offset = ((16 - ((long)&srs_estimated_channel_freq[0][0][subcarrier_offset + nr_srs_info->k_0_p[0][0]])) & 0xF) >> 2; // >> 2 <=> /sizeof(int32_t)
uint8_t mem_offset = ((16 - ((long)&srs_estimated_channel_freq[0][0][subcarrier_offset + nr_srs_info->k_0_p[0][0]])) & 0xF) >> 2; // >> 2 <=> /sizeof(int32_t)
// filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0}
// The End of OFDM symbol corresponds to the position of last 16384 in the filter
// The multadd_real_vector_complex_scalar applies the remaining 8 zeros of filter, therefore, to avoid a buffer overflow,
// we added 8 in the array size
int32_t srs_est[frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols) + mem_offset + 8] __attribute__ ((aligned(32)));
// filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0}
// The End of OFDM symbol corresponds to the position of last 16384 in the filter
// The multadd_real_vector_complex_scalar applies the remaining 8 zeros of filter, therefore, to avoid a buffer overflow,
// we added 8 in the array size
int32_t srs_est[frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols) + mem_offset + 8] __attribute__ ((aligned(32)));
for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) {
for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) {
for (int p_index = 0; p_index < N_ap; p_index++) {
for (int p_index = 0; p_index < N_ap; p_index++) {
memset(srs_ls_estimated_channel, 0, frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols)*sizeof(c16_t));
memset(srs_est, 0, (frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols) + mem_offset)*sizeof(int32_t));
memset(srs_ls_estimated_channel, 0, frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols)*sizeof(c16_t));
memset(srs_est, 0, (frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols) + mem_offset)*sizeof(int32_t));
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"====================== UE port %d --> gNB Rx antenna %i ======================\n", p_index, ant);
LOG_I(NR_PHY,"====================== UE port %d --> gNB Rx antenna %i ======================\n", p_index, ant);
#endif
uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
if (subcarrier>frame_parms->ofdm_symbol_size) {
subcarrier -= frame_parms->ofdm_symbol_size;
}
uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
if (subcarrier>frame_parms->ofdm_symbol_size) {
subcarrier -= frame_parms->ofdm_symbol_size;
}
int16_t *srs_estimated_channel16 = (int16_t *)&srs_est[subcarrier + mem_offset];
int16_t *srs_estimated_channel16 = (int16_t *)&srs_est[subcarrier + mem_offset];
for (int k = 0; k < M_sc_b_SRS; k++) {
for (int k = 0; k < M_sc_b_SRS; k++) {
if (k%fd_cdm==0) {
if (k%fd_cdm==0) {
ls_estimated[0] = 0;
ls_estimated[1] = 0;
uint16_t subcarrier_cdm = subcarrier;
ls_estimated[0] = 0;
ls_estimated[1] = 0;
uint16_t subcarrier_cdm = subcarrier;
for (int cdm_idx = 0; cdm_idx < fd_cdm; cdm_idx++) {
int16_t generated_real = srs_generated_signal[p_index][subcarrier_cdm].r;
int16_t generated_imag = srs_generated_signal[p_index][subcarrier_cdm].i;
for (int cdm_idx = 0; cdm_idx < fd_cdm; cdm_idx++) {
int16_t generated_real = srs_generated_signal[p_index][subcarrier_cdm].r;
int16_t generated_imag = srs_generated_signal[p_index][subcarrier_cdm].i;
int16_t received_real = ((c16_t*)srs_received_signal[ant])[subcarrier_cdm].r;
int16_t received_imag = ((c16_t*)srs_received_signal[ant])[subcarrier_cdm].i;
int16_t received_real = ((c16_t*)srs_received_signal[ant])[subcarrier_cdm].r;
int16_t received_imag = ((c16_t*)srs_received_signal[ant])[subcarrier_cdm].i;
// We know that nr_srs_info->srs_generated_signal_bits bits are enough to represent the generated_real and generated_imag.
// So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16 bits.
ls_estimated[0] += (int16_t)(((int32_t)generated_real*received_real + (int32_t)generated_imag*received_imag)>>nr_srs_info->srs_generated_signal_bits);
ls_estimated[1] += (int16_t)(((int32_t)generated_real*received_imag - (int32_t)generated_imag*received_real)>>nr_srs_info->srs_generated_signal_bits);
// We know that nr_srs_info->srs_generated_signal_bits bits are enough to represent the generated_real and generated_imag.
// So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16 bits.
ls_estimated[0] += (int16_t)(((int32_t)generated_real*received_real + (int32_t)generated_imag*received_imag)>>nr_srs_info->srs_generated_signal_bits);
ls_estimated[1] += (int16_t)(((int32_t)generated_real*received_imag - (int32_t)generated_imag*received_real)>>nr_srs_info->srs_generated_signal_bits);
// Subcarrier increment
subcarrier_cdm += K_TC;
if (subcarrier_cdm >= frame_parms->ofdm_symbol_size) {
subcarrier_cdm=subcarrier_cdm-frame_parms->ofdm_symbol_size;
}
}
}
// Subcarrier increment
subcarrier_cdm += K_TC;
if (subcarrier_cdm >= frame_parms->ofdm_symbol_size) {
subcarrier_cdm=subcarrier_cdm-frame_parms->ofdm_symbol_size;
}
}
}
srs_ls_estimated_channel[subcarrier].r = ls_estimated[0];
srs_ls_estimated_channel[subcarrier].i = ls_estimated[1];
srs_ls_estimated_channel[subcarrier].r = ls_estimated[0];
srs_ls_estimated_channel[subcarrier].i = ls_estimated[1];
#ifdef SRS_DEBUG
int subcarrier_log = subcarrier-subcarrier_offset;
if(subcarrier_log < 0) {
subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size;
}
if(subcarrier_log%12 == 0) {
LOG_I(NR_PHY,"------------------------------------ %d ------------------------------------\n", subcarrier_log/12);
LOG_I(NR_PHY,"\t __genRe________genIm__|____rxRe_________rxIm__|____lsRe________lsIm_\n");
}
LOG_I(NR_PHY,"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
subcarrier_log,
((c16_t*)srs_generated_signal[p_index])[subcarrier].r, ((c16_t*)srs_generated_signal[p_index])[subcarrier].i,
((c16_t*)srs_received_signal[ant])[subcarrier].r, ((c16_t*)srs_received_signal[ant])[subcarrier].i,
ls_estimated[0], ls_estimated[1]);
int subcarrier_log = subcarrier-subcarrier_offset;
if(subcarrier_log < 0) {
subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size;
}
if(subcarrier_log%12 == 0) {
LOG_I(NR_PHY,"------------------------------------ %d ------------------------------------\n", subcarrier_log/12);
LOG_I(NR_PHY,"\t __genRe________genIm__|____rxRe_________rxIm__|____lsRe________lsIm_\n");
}
LOG_I(NR_PHY,"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
subcarrier_log,
((c16_t*)srs_generated_signal[p_index])[subcarrier].r, ((c16_t*)srs_generated_signal[p_index])[subcarrier].i,
((c16_t*)srs_received_signal[ant])[subcarrier].r, ((c16_t*)srs_received_signal[ant])[subcarrier].i,
ls_estimated[0], ls_estimated[1]);
#endif
const uint16_t sc_offset = subcarrier + mem_offset;
// Channel interpolation
if(srs_pdu->comb_size == 0) {
if(k == 0) { // First subcarrier case
// filt8_start is {12288,8192,4096,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt8_start, ls_estimated, srs_estimated_channel16, 8);
} else if(subcarrier < K_TC) { // Start of OFDM symbol case
// filt8_start is {12288,8192,4096,0,0,0,0,0}
srs_estimated_channel16 = (int16_t *)&srs_est[subcarrier];
const short *filter = mem_offset == 0 ? filt8_start : filt8_start_shift2;
multadd_real_vector_complex_scalar(filter, ls_estimated, srs_estimated_channel16, 8);
} else if((subcarrier+K_TC)>=frame_parms->ofdm_symbol_size || k == (M_sc_b_SRS-1)) { // End of OFDM symbol or last subcarrier cases
// filt8_end is {4096,8192,12288,16384,0,0,0,0}
const short *filter = mem_offset == 0 || k == (M_sc_b_SRS - 1) ? filt8_end : filt8_end_shift2;
multadd_real_vector_complex_scalar(filter, ls_estimated, srs_estimated_channel16, 8);
} else if(k%2 == 1) { // 1st middle case
// filt8_middle2 is {4096,8192,8192,8192,4096,0,0,0}
multadd_real_vector_complex_scalar(filt8_middle2, ls_estimated, srs_estimated_channel16, 8);
} else if(k%2 == 0) { // 2nd middle case
// filt8_middle4 is {0,0,4096,8192,8192,8192,4096,0}
multadd_real_vector_complex_scalar(filt8_middle4, ls_estimated, srs_estimated_channel16, 8);
srs_estimated_channel16 = (int16_t *)&srs_est[sc_offset];
}
} else {
if(k == 0) { // First subcarrier case
// filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt16_start, ls_estimated, srs_estimated_channel16, 16);
} else if(subcarrier < K_TC) { // Start of OFDM symbol case
srs_estimated_channel16 = (int16_t *)&srs_est[sc_offset];
// filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt16_start, ls_estimated, srs_estimated_channel16, 16);
} else if((subcarrier+K_TC)>=frame_parms->ofdm_symbol_size || k == (M_sc_b_SRS-1)) { // End of OFDM symbol or last subcarrier cases
// filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt16_end, ls_estimated, srs_estimated_channel16, 16);
} else { // Middle case
// filt16_middle4 is {4096,8192,8192,8192,8192,8192,8192,8192,4096,0,0,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt16_middle4, ls_estimated, srs_estimated_channel16, 16);
srs_estimated_channel16 = (int16_t *)&srs_est[sc_offset];
}
}
// Subcarrier increment
subcarrier += K_TC;
if (subcarrier >= frame_parms->ofdm_symbol_size) {
subcarrier=subcarrier-frame_parms->ofdm_symbol_size;
}
} // for (int k = 0; k < M_sc_b_SRS; k++)
memcpy(&srs_estimated_channel_freq[ant][p_index][0],
&srs_est[mem_offset],
(frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols))*sizeof(int32_t));
// Compute noise
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
if (subcarrier>frame_parms->ofdm_symbol_size) {
subcarrier -= frame_parms->ofdm_symbol_size;
}
uint16_t base_idx = ant*N_ap*M_sc_b_SRS + p_index*M_sc_b_SRS;
for (int k = 0; k < M_sc_b_SRS; k++) {
ch_real[base_idx+k] = ((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].r;
ch_imag[base_idx+k] = ((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].i;
noise_real[base_idx+k] = abs(srs_ls_estimated_channel[subcarrier].r - ch_real[base_idx+k]);
noise_imag[base_idx+k] = abs(srs_ls_estimated_channel[subcarrier].i - ch_imag[base_idx+k]);
subcarrier += K_TC;
if (subcarrier >= frame_parms->ofdm_symbol_size) {
subcarrier=subcarrier-frame_parms->ofdm_symbol_size;
}
}
const uint16_t sc_offset = subcarrier + mem_offset;
// Channel interpolation
if(srs_pdu->comb_size == 0) {
if(k == 0) { // First subcarrier case
// filt8_start is {12288,8192,4096,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt8_start, ls_estimated, srs_estimated_channel16, 8);
} else if(subcarrier < K_TC) { // Start of OFDM symbol case
// filt8_start is {12288,8192,4096,0,0,0,0,0}
srs_estimated_channel16 = (int16_t *)&srs_est[subcarrier];
const short *filter = mem_offset == 0 ? filt8_start : filt8_start_shift2;
multadd_real_vector_complex_scalar(filter, ls_estimated, srs_estimated_channel16, 8);
} else if((subcarrier+K_TC)>=frame_parms->ofdm_symbol_size || k == (M_sc_b_SRS-1)) { // End of OFDM symbol or last subcarrier cases
// filt8_end is {4096,8192,12288,16384,0,0,0,0}
const short *filter = mem_offset == 0 || k == (M_sc_b_SRS - 1) ? filt8_end : filt8_end_shift2;
multadd_real_vector_complex_scalar(filter, ls_estimated, srs_estimated_channel16, 8);
} else if(k%2 == 1) { // 1st middle case
// filt8_middle2 is {4096,8192,8192,8192,4096,0,0,0}
multadd_real_vector_complex_scalar(filt8_middle2, ls_estimated, srs_estimated_channel16, 8);
} else if(k%2 == 0) { // 2nd middle case
// filt8_middle4 is {0,0,4096,8192,8192,8192,4096,0}
multadd_real_vector_complex_scalar(filt8_middle4, ls_estimated, srs_estimated_channel16, 8);
srs_estimated_channel16 = (int16_t *)&srs_est[sc_offset];
}
} else {
if(k == 0) { // First subcarrier case
// filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt16_start, ls_estimated, srs_estimated_channel16, 16);
} else if(subcarrier < K_TC) { // Start of OFDM symbol case
srs_estimated_channel16 = (int16_t *)&srs_est[sc_offset];
// filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt16_start, ls_estimated, srs_estimated_channel16, 16);
} else if((subcarrier+K_TC)>=frame_parms->ofdm_symbol_size || k == (M_sc_b_SRS-1)) { // End of OFDM symbol or last subcarrier cases
// filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt16_end, ls_estimated, srs_estimated_channel16, 16);
} else { // Middle case
// filt16_middle4 is {4096,8192,8192,8192,8192,8192,8192,8192,4096,0,0,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt16_middle4, ls_estimated, srs_estimated_channel16, 16);
srs_estimated_channel16 = (int16_t *)&srs_est[sc_offset];
}
}
// Subcarrier increment
subcarrier += K_TC;
if (subcarrier >= frame_parms->ofdm_symbol_size) {
subcarrier=subcarrier-frame_parms->ofdm_symbol_size;
}
} // for (int k = 0; k < M_sc_b_SRS; k++)
memcpy(&srs_estimated_channel_freq[ant][p_index][0],
&srs_est[mem_offset],
(frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols))*sizeof(int32_t));
// Compute noise
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
if (subcarrier>frame_parms->ofdm_symbol_size) {
subcarrier -= frame_parms->ofdm_symbol_size;
}
uint16_t base_idx = ant*N_ap*M_sc_b_SRS + p_index*M_sc_b_SRS;
for (int k = 0; k < M_sc_b_SRS; k++) {
ch_real[base_idx+k] = ((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].r;
ch_imag[base_idx+k] = ((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].i;
noise_real[base_idx+k] = abs(srs_ls_estimated_channel[subcarrier].r - ch_real[base_idx+k]);
noise_imag[base_idx+k] = abs(srs_ls_estimated_channel[subcarrier].i - ch_imag[base_idx+k]);
subcarrier += K_TC;
if (subcarrier >= frame_parms->ofdm_symbol_size) {
subcarrier=subcarrier-frame_parms->ofdm_symbol_size;
}
}
#ifdef SRS_DEBUG
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
if (subcarrier>frame_parms->ofdm_symbol_size) {
subcarrier -= frame_parms->ofdm_symbol_size;
}
for (int k = 0; k < K_TC*M_sc_b_SRS; k++) {
int subcarrier_log = subcarrier-subcarrier_offset;
if(subcarrier_log < 0) {
subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size;
}
if(subcarrier_log%12 == 0) {
LOG_I(NR_PHY,"------------------------------------- %d -------------------------------------\n", subcarrier_log/12);
LOG_I(NR_PHY,"\t __lsRe__________lsIm__|____intRe_______intIm__|____noiRe_______noiIm__\n");
}
LOG_I(NR_PHY,"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
subcarrier_log,
srs_ls_estimated_channel[subcarrier].r,
srs_ls_estimated_channel[subcarrier].i,
((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].r,
((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].i,
noise_real[base_idx+(k/K_TC)], noise_imag[base_idx+(k/K_TC)]);
// Subcarrier increment
subcarrier++;
if (subcarrier >= frame_parms->ofdm_symbol_size) {
subcarrier=subcarrier-frame_parms->ofdm_symbol_size;
}
}
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
if (subcarrier>frame_parms->ofdm_symbol_size) {
subcarrier -= frame_parms->ofdm_symbol_size;
}
for (int k = 0; k < K_TC*M_sc_b_SRS; k++) {
int subcarrier_log = subcarrier-subcarrier_offset;
if(subcarrier_log < 0) {
subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size;
}
if(subcarrier_log%12 == 0) {
LOG_I(NR_PHY,"------------------------------------- %d -------------------------------------\n", subcarrier_log/12);
LOG_I(NR_PHY,"\t __lsRe__________lsIm__|____intRe_______intIm__|____noiRe_______noiIm__\n");
}
LOG_I(NR_PHY,"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
subcarrier_log,
srs_ls_estimated_channel[subcarrier].r,
srs_ls_estimated_channel[subcarrier].i,
((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].r,
((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].i,
noise_real[base_idx+(k/K_TC)], noise_imag[base_idx+(k/K_TC)]);
// Subcarrier increment
subcarrier++;
if (subcarrier >= frame_parms->ofdm_symbol_size) {
subcarrier=subcarrier-frame_parms->ofdm_symbol_size;
}
}
#endif
// Convert to time domain
freq2time(gNB->frame_parms.ofdm_symbol_size,
(int16_t*) srs_estimated_channel_freq[ant][p_index],
(int16_t*) srs_estimated_channel_time[ant][p_index]);
// Convert to time domain
freq2time(gNB->frame_parms.ofdm_symbol_size,
(int16_t*) srs_estimated_channel_freq[ant][p_index],
(int16_t*) srs_estimated_channel_time[ant][p_index]);
memcpy(&srs_estimated_channel_time_shifted[ant][p_index][0],
&srs_estimated_channel_time[ant][p_index][gNB->frame_parms.ofdm_symbol_size>>1],
(gNB->frame_parms.ofdm_symbol_size>>1)*sizeof(int32_t));
memcpy(&srs_estimated_channel_time_shifted[ant][p_index][0],
&srs_estimated_channel_time[ant][p_index][gNB->frame_parms.ofdm_symbol_size>>1],
(gNB->frame_parms.ofdm_symbol_size>>1)*sizeof(int32_t));
memcpy(&srs_estimated_channel_time_shifted[ant][p_index][gNB->frame_parms.ofdm_symbol_size>>1],
&srs_estimated_channel_time[ant][p_index][0],
(gNB->frame_parms.ofdm_symbol_size>>1)*sizeof(int32_t));
memcpy(&srs_estimated_channel_time_shifted[ant][p_index][gNB->frame_parms.ofdm_symbol_size>>1],
&srs_estimated_channel_time[ant][p_index][0],
(gNB->frame_parms.ofdm_symbol_size>>1)*sizeof(int32_t));
} // for (int p_index = 0; p_index < N_ap; p_index++)
} // for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++)
} // for (int p_index = 0; p_index < N_ap; p_index++)
} // for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++)
// Compute signal power
uint32_t signal_power = calc_power(ch_real, arr_len) + calc_power(ch_imag, arr_len);
// Compute signal power
uint32_t signal_power = calc_power(ch_real, arr_len) + calc_power(ch_imag, arr_len);
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"signal_power = %u\n", signal_power);
LOG_I(NR_PHY,"signal_power = %u\n", signal_power);
#endif
if (signal_power == 0) {
LOG_W(NR_PHY, "Received SRS signal power is 0\n");
return -1;
}
// Compute noise power
const uint8_t signal_power_bits = log2_approx(signal_power);
const uint8_t factor_bits = signal_power_bits < 32 ? 32 - signal_power_bits : 0; // 32 due to input of dB_fixed(uint32_t x)
const int32_t factor_dB = dB_fixed(1<<factor_bits);
const uint8_t srs_symbols_per_rb = srs_pdu->comb_size == 0 ? 6 : 3;
const uint8_t n_noise_est = frame_parms->nb_antennas_rx*N_ap*srs_symbols_per_rb;
uint64_t sum_re = 0;
uint64_t sum_re2 = 0;
uint64_t sum_im = 0;
uint64_t sum_im2 = 0;
for (int rb = 0; rb < m_SRS_b; rb++) {
sum_re = 0;
sum_re2 = 0;
sum_im = 0;
sum_im2 = 0;
for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) {
for (int p_index = 0; p_index < N_ap; p_index++) {
uint16_t base_idx = ant*N_ap*M_sc_b_SRS + p_index*M_sc_b_SRS + rb*srs_symbols_per_rb;
for (int srs_symb = 0; srs_symb < srs_symbols_per_rb; srs_symb++) {
sum_re = sum_re + noise_real[base_idx+srs_symb];
sum_re2 = sum_re2 + noise_real[base_idx+srs_symb]*noise_real[base_idx+srs_symb];
sum_im = sum_im + noise_imag[base_idx+srs_symb];
sum_im2 = sum_im2 + noise_imag[base_idx+srs_symb]*noise_imag[base_idx+srs_symb];
} // for (int srs_symb = 0; srs_symb < srs_symbols_per_rb; srs_symb++)
} // for (int p_index = 0; p_index < N_ap; p_index++)
} // for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++)
noise_power_per_rb[rb] = max(sum_re2 / n_noise_est - (sum_re / n_noise_est) * (sum_re / n_noise_est) +
sum_im2 / n_noise_est - (sum_im / n_noise_est) * (sum_im / n_noise_est), 1);
snr_per_rb[rb] = dB_fixed((int32_t)((signal_power<<factor_bits)/noise_power_per_rb[rb])) - factor_dB;
if (signal_power == 0) {
LOG_W(NR_PHY, "Received SRS signal power is 0\n");
return -1;
}
// Compute noise power
const uint8_t signal_power_bits = log2_approx(signal_power);
const uint8_t factor_bits = signal_power_bits < 32 ? 32 - signal_power_bits : 0; // 32 due to input of dB_fixed(uint32_t x)
const int32_t factor_dB = dB_fixed(1<<factor_bits);
const uint8_t srs_symbols_per_rb = srs_pdu->comb_size == 0 ? 6 : 3;
const uint8_t n_noise_est = frame_parms->nb_antennas_rx*N_ap*srs_symbols_per_rb;
uint64_t sum_re = 0;
uint64_t sum_re2 = 0;
uint64_t sum_im = 0;
uint64_t sum_im2 = 0;
for (int rb = 0; rb < m_SRS_b; rb++) {
sum_re = 0;
sum_re2 = 0;
sum_im = 0;
sum_im2 = 0;
for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) {
for (int p_index = 0; p_index < N_ap; p_index++) {
uint16_t base_idx = ant*N_ap*M_sc_b_SRS + p_index*M_sc_b_SRS + rb*srs_symbols_per_rb;
for (int srs_symb = 0; srs_symb < srs_symbols_per_rb; srs_symb++) {
sum_re = sum_re + noise_real[base_idx+srs_symb];
sum_re2 = sum_re2 + noise_real[base_idx+srs_symb]*noise_real[base_idx+srs_symb];
sum_im = sum_im + noise_imag[base_idx+srs_symb];
sum_im2 = sum_im2 + noise_imag[base_idx+srs_symb]*noise_imag[base_idx+srs_symb];
} // for (int srs_symb = 0; srs_symb < srs_symbols_per_rb; srs_symb++)
} // for (int p_index = 0; p_index < N_ap; p_index++)
} // for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++)
noise_power_per_rb[rb] = max(sum_re2 / n_noise_est - (sum_re / n_noise_est) * (sum_re / n_noise_est) +
sum_im2 / n_noise_est - (sum_im / n_noise_est) * (sum_im / n_noise_est), 1);
snr_per_rb[rb] = dB_fixed((int32_t)((signal_power<<factor_bits)/noise_power_per_rb[rb])) - factor_dB;
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"noise_power_per_rb[%i] = %i, snr_per_rb[%i] = %i dB\n", rb, noise_power_per_rb[rb], rb, snr_per_rb[rb]);
LOG_I(NR_PHY,"noise_power_per_rb[%i] = %i, snr_per_rb[%i] = %i dB\n", rb, noise_power_per_rb[rb], rb, snr_per_rb[rb]);
#endif
} // for (int rb = 0; rb < m_SRS_b; rb++)
} // for (int rb = 0; rb < m_SRS_b; rb++)
const uint32_t noise_power = max(calc_power(noise_real, arr_len) + calc_power(noise_imag, arr_len), 1);
const uint32_t noise_power = max(calc_power(noise_real, arr_len) + calc_power(noise_imag, arr_len), 1);
*snr = dB_fixed((int32_t)((signal_power<<factor_bits)/(noise_power))) - factor_dB;
*snr = dB_fixed((int32_t)((signal_power<<factor_bits)/(noise_power))) - factor_dB;
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"noise_power = %u, SNR = %i dB\n", noise_power, *snr);
LOG_I(NR_PHY,"noise_power = %u, SNR = %i dB\n", noise_power, *snr);
#endif
return 0;
return 0;
}
\ No newline at end of file
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.0 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <string.h>
#include "nr_ul_estimation.h"
#include "PHY/sse_intrin.h"
#include "PHY/NR_REFSIG/nr_refsig.h"
#include "PHY/NR_REFSIG/dmrs_nr.h"
#include "PHY/NR_REFSIG/ptrs_nr.h"
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
#include "PHY/NR_UE_TRANSPORT/srs_modulation_nr.h"
#include "PHY/NR_UE_ESTIMATION/filt16a_32.h"
#include "PHY/NR_REFSIG/ul_ref_seq_nr.h"
#include "executables/softmodem-common.h"
//#define DEBUG_CH
//#define DEBUG_PUSCH
//#define SRS_DEBUG
#define NO_INTERP 1
#define dBc(x,y) (dB_fixed(((int32_t)(x))*(x) + ((int32_t)(y))*(y)))
__attribute__((always_inline)) inline c16_t c32x16cumulVectVectWithSteps(c16_t *in1,
int *offset1,
const int step1,
c16_t *in2,
int *offset2,
const int step2,
const int modulo2,
const int N) {
int localOffset1=*offset1;
int localOffset2=*offset2;
c32_t cumul={0};
for (int i=0; i<N; i++) {
cumul=c32x16maddShift(in1[localOffset1], in2[localOffset2], cumul, 15);
localOffset1+=step1;
localOffset2= (localOffset2 + step2) % modulo2;
}
*offset1=localOffset1;
*offset2=localOffset2;
return c16x32div(cumul, N);
}
int inner_channel_estimation(inner_channel_estimation_params *rdata) {
PHY_VARS_gNB *gNB = rdata->gNB;
int aarx = rdata->aarx;
const int symbol_offset = rdata->symbol_offset;
c16_t **ul_ch_estimates = rdata->ul_ch_estimates;
int nl = rdata->nl;
int ch_offset = rdata->ch_offset;
const int symbolSize = rdata->symbolSize;
nfapi_nr_pusch_pdu_t *pusch_pdu = rdata->pusch_pdu;
const int chest_freq = rdata->chest_freq;
c16_t *pilot = rdata->pilot;
const int k0 = rdata->k0;
const int nb_rb_pusch = rdata->nb_rb_pusch;
unsigned short p = rdata->p;
const int soffset = rdata->soffset;
int *max_ch = rdata->max_ch;
c16_t *ul_ls_est = rdata->ul_ls_est;
NR_gNB_PUSCH *pusch_vars = rdata->pusch_vars;
delay_t *delay = rdata->delay;
uint64_t noise_amp2 = rdata->noise_amp2;
int nest_count = rdata->nest_count;
const int nushift = rdata->nushift;
c16_t *rxdataF = (c16_t *)&gNB->common_vars.rxdataF[aarx][symbol_offset];
c16_t *ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][ch_offset];
memset(ul_ch,0,sizeof(*ul_ch)*symbolSize);
#ifdef DEBUG_PUSCH
LOG_I(PHY, "In %s symbol_offset %d, nushift %d\n", __FUNCTION__, symbol_offset, nushift);
LOG_I(PHY, "In %s ch est pilot, N_RB_UL %d\n", __FUNCTION__, gNB->frame_parms.N_RB_UL);
LOG_I(PHY, "In %s bwp_start_subcarrier %d, k0 %d, first_carrier %d, nb_rb_pusch %d\n", __FUNCTION__, bwp_start_subcarrier, k0, gNB->frame_parms.first_carrier_offset, nb_rb_pusch);
LOG_I(PHY, "In %s ul_ch addr %p nushift %d\n", __FUNCTION__, ul_ch, nushift);
#endif
if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1 && chest_freq == 0) {
c16_t *pil = pilot;
int re_offset = k0;
LOG_D(PHY,"PUSCH estimation DMRS type 1, Freq-domain interpolation");
// For configuration type 1: k = 4*n + 2*k' + delta,
// where k' is 0 or 1, and delta is in Table 6.4.1.1.3-1 from TS 38.211
int pilot_cnt = 0;
int delta = nr_pusch_dmrs_delta(pusch_dmrs_type1, p);
for (int n = 0; n < 3 * nb_rb_pusch; n++) {
// LS estimation
c32_t ch = {0};
for (int k_line = 0; k_line <= 1; k_line++) {
re_offset = (k0 + (n << 2) + (k_line << 1) + delta) % symbolSize;
ch = c32x16maddShift(*pil, rxdataF[soffset + re_offset], ch, 16);
pil++;
}
c16_t ch16 = {.r = (int16_t)ch.r, .i = (int16_t)ch.i};
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) {
ul_ls_est[k] = ch16;
}
pilot_cnt += 2;
}
nr_est_delay(gNB->frame_parms.ofdm_symbol_size, ul_ls_est, (c16_t *)pusch_vars->ul_ch_estimates_time[aarx], delay);
int delay_idx = get_delay_idx(delay->est_delay, MAX_DELAY_COMP);
c16_t *ul_delay_table = gNB->frame_parms.delay_table[delay_idx];
#ifdef DEBUG_PUSCH
printf("Estimated delay = %i\n", delay->est_delay >> 1);
#endif
pilot_cnt = 0;
for (int n = 0; n < 3*nb_rb_pusch; n++) {
// Channel interpolation
for (int k_line = 0; k_line <= 1; k_line++) {
// Apply delay
int k = pilot_cnt << 1;
c16_t ch16 = c16mulShift(ul_ls_est[k], ul_delay_table[k], 8);
#ifdef DEBUG_PUSCH
re_offset = (k0 + (n << 2) + (k_line << 1)) % symbolSize;
c16_t *rxF = &rxdataF[soffset + re_offset];
printf("pilot %4d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d)\n",
pilot_cnt, pil->r, pil->i, rxF->r, rxF->i, ch.r, ch.i);
#endif
if (pilot_cnt == 0) {
c16multaddVectRealComplex(filt16_ul_p0, &ch16, ul_ch, 16);
} else if (pilot_cnt == 1 || pilot_cnt == 2) {
c16multaddVectRealComplex(filt16_ul_p1p2, &ch16, ul_ch, 16);
} else if (pilot_cnt == (6 * nb_rb_pusch - 1)) {
c16multaddVectRealComplex(filt16_ul_last, &ch16, ul_ch, 16);
} else {
c16multaddVectRealComplex(filt16_ul_middle, &ch16, ul_ch, 16);
if (pilot_cnt % 2 == 0) {
ul_ch += 4;
}
}
pilot_cnt++;
}
}
// Revert delay
pilot_cnt = 0;
ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][ch_offset];
int inv_delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP);
c16_t *ul_inv_delay_table = gNB->frame_parms.delay_table[inv_delay_idx];
for (int n = 0; n < 3 * nb_rb_pusch; n++) {
for (int k_line = 0; k_line <= 1; k_line++) {
int k = pilot_cnt << 1;
ul_ch[k] = c16mulShift(ul_ch[k], ul_inv_delay_table[k], 8);
ul_ch[k + 1] = c16mulShift(ul_ch[k + 1], ul_inv_delay_table[k + 1], 8);
noise_amp2 += c16amp2(c16sub(ul_ls_est[k], ul_ch[k]));
noise_amp2 += c16amp2(c16sub(ul_ls_est[k + 1], ul_ch[k + 1]));
#ifdef DEBUG_PUSCH
re_offset = (k0 + (n << 2) + (k_line << 1)) % symbolSize;
c16_t *rxF = &rxdataF[soffset + re_offset];
printf("ch -> (%4d,%4d), ch_inter -> (%4d,%4d)\n", ul_ls_est[k].r, ul_ls_est[k].i, ul_ch[k].r, ul_ch[k].i);
#endif
pilot_cnt++;
nest_count += 2;
}
}
} else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type2 && chest_freq == 0) { // pusch_dmrs_type2 |p_r,p_l,d,d,d,d,p_r,p_l,d,d,d,d|
LOG_D(PHY, "PUSCH estimation DMRS type 2, Freq-domain interpolation\n");
c16_t *pil = pilot;
c16_t *rx = &rxdataF[soffset + nushift];
for (int n = 0; n < nb_rb_pusch * NR_NB_SC_PER_RB; n += 6) {
c16_t ch0 = c16mulShift(*pil, rx[(k0 + n) % symbolSize], 15);
pil++;
c16_t ch1 = c16mulShift(*pil, rx[(k0 + n + 1) % symbolSize], 15);
pil++;
c16_t ch = c16addShift(ch0, ch1, 1);
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
multadd_real_four_symbols_vector_complex_scalar(filt8_rep4, &ch, &ul_ls_est[n]);
ul_ls_est[n + 4] = ch;
ul_ls_est[n + 5] = ch;
noise_amp2 += c16amp2(c16sub(ch0, ch));
nest_count++;
}
// Delay compensation
nr_est_delay(gNB->frame_parms.ofdm_symbol_size, ul_ls_est, (c16_t *)pusch_vars->ul_ch_estimates_time[aarx], delay);
int delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP);
c16_t *ul_delay_table = gNB->frame_parms.delay_table[delay_idx];
for (int n = 0; n < nb_rb_pusch * NR_NB_SC_PER_RB; n++) {
ul_ch[n] = c16mulShift(ul_ls_est[n], ul_delay_table[n % 6], 8);
}
}
else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1) { // this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 6 DMRS REs and use a common value for the whole PRB
LOG_D(PHY,"PUSCH estimation DMRS type 1, no Freq-domain interpolation\n");
c16_t *rxF = &rxdataF[soffset + nushift];
int pil_offset = 0;
int re_offset = k0;
c16_t ch;
// First PRB
ch=c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6);
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
c16multaddVectRealComplex(filt8_avlip0, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip1, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip2, &ch, ul_ch, 8);
ul_ch -= 12;
#endif
for (int pilot_cnt=6; pilot_cnt<6*(nb_rb_pusch-1); pilot_cnt += 6) {
ch=c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6);
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
ul_ch[3].r += (ch.r * 1365)>>15; // 1/12*16384
ul_ch[3].i += (ch.i * 1365)>>15; // 1/12*16384
ul_ch += 4;
c16multaddVectRealComplex(filt8_avlip3, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip4, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip5, &ch, ul_ch, 8);
ul_ch -= 8;
#endif
}
// Last PRB
ch=c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6);
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
ul_ch[3].r += (ch.r * 1365)>>15; // 1/12*16384
ul_ch[3].i += (ch.i * 1365)>>15; // 1/12*16384
ul_ch += 4;
c16multaddVectRealComplex(filt8_avlip3, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip6, &ch, ul_ch, 8);
#endif
} else { // this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 4 DMRS REs and use a common value for the whole PRB
LOG_D(PHY,"PUSCH estimation DMRS type 2, no Freq-domain interpolation");
c16_t *pil = pilot;
int re_offset = k0;
c32_t ch0={0};
//First PRB
ch0=c32x16mulShift(*pil,
rxdataF[soffset + nushift + re_offset],
15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil,
rxdataF[nushift+re_offset],
ch0,
15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch0=c32x16maddShift(*pil,
rxdataF[nushift+re_offset],
ch0,
15);
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil,
rxdataF[nushift+re_offset],
ch0,
15);
pil++;
re_offset = (re_offset+5) % symbolSize;
c16_t ch=c16x32div(ch0, 4);
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
c16multaddVectRealComplex(filt8_avlip0, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip1, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip2, &ch, ul_ch, 8);
ul_ch -= 12;
#endif
for (int pilot_cnt=4; pilot_cnt<4*(nb_rb_pusch-1); pilot_cnt += 4) {
c32_t ch0;
ch0=c32x16mulShift(*pil, rxdataF[nushift+re_offset], 15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch=c16x32div(ch0, 4);
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
ul_ch[3] = c16maddShift(ch, (c16_t){1365, 1365}, (c16_t){0, 0}, 15); // 1365 = 1/12*16384 (full range is +/- 32768)
ul_ch += 4;
c16multaddVectRealComplex(filt8_avlip3, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip4, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip5, &ch, ul_ch, 8);
ul_ch -= 8;
#endif
}
// Last PRB
ch0=c32x16mulShift(*pil, rxdataF[nushift+re_offset], 15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+1) % symbolSize;
ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15);
pil++;
re_offset = (re_offset+5) % symbolSize;
ch=c16x32div(ch0, 4);
#if NO_INTERP
for (c16_t *end=ul_ch+12; ul_ch<end; ul_ch++)
*ul_ch=ch;
#else
ul_ch[3] = c16maddShift(ch, (c16_t){1365, 1365}, (c16_t){0, 0}, 15); // 1365 = 1/12*16384 (full range is +/- 32768)
ul_ch += 4;
c16multaddVectRealComplex(filt8_avlip3, &ch, ul_ch, 8);
ul_ch += 8;
c16multaddVectRealComplex(filt8_avlip6, &ch, ul_ch, 8);
#endif
}
#ifdef DEBUG_PUSCH
ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][ch_offset];
for (int idxP = 0; idxP < ceil((float)nb_rb_pusch * 12 / 8); idxP++) {
for (int idxI = 0; idxI < 8; idxI++) {
printf("%d\t%d\t", ul_ch[idxP * 8 + idxI].r, ul_ch[idxP * 8 + idxI].i);
}
printf("%d\n", idxP);
}
#endif
// value update of rdata to be passed to the next inner call
rdata->max_ch = max_ch; // Placeholder for max channel value update
rdata->noise_amp2 = noise_amp2; // Placeholder for noise amplitude squared update
delay->est_delay = rdata->delay->est_delay; // Placeholder for estimated delay update
nest_count = rdata->nest_count; // Placeholder for nested count update
rdata->ul_ls_est = ul_ls_est; // Placeholder for uplink least square estimation
return 0;
}
int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
unsigned char Ns,
int nl,
unsigned short p,
unsigned char symbol,
int ul_id,
unsigned short bwp_start_subcarrier,
nfapi_nr_pusch_pdu_t *pusch_pdu,
int *max_ch,
uint32_t *nvar)
{
c16_t pilot[3280] __attribute__((aligned(32)));
const int chest_freq = gNB->chest_freq;
#ifdef DEBUG_CH
FILE *debug_ch_est;
debug_ch_est = fopen("debug_ch_est.txt","w");
#endif
NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ul_id];
c16_t **ul_ch_estimates = (c16_t **)pusch_vars->ul_ch_estimates;
const int symbolSize = gNB->frame_parms.ofdm_symbol_size;
const int soffset = (Ns & 3) * gNB->frame_parms.symbols_per_slot*symbolSize;
const int nushift = (p >> 1) & 1;
int ch_offset = symbolSize*symbol;
const int symbol_offset = symbolSize*symbol;
const int k0 = bwp_start_subcarrier;
const int nb_rb_pusch = pusch_pdu->rb_size;
LOG_D(PHY, "ch_offset %d, soffset %d, symbol_offset %d, OFDM size %d, Ns = %d, k0 = %d, symbol %d\n",
ch_offset, soffset,
symbol_offset,
symbolSize,
Ns,
k0,
symbol);
//------------------generate DMRS------------------//
if(pusch_pdu->ul_dmrs_scrambling_id != gNB->pusch_gold_init[pusch_pdu->scid]) {
gNB->pusch_gold_init[pusch_pdu->scid] = pusch_pdu->ul_dmrs_scrambling_id;
nr_gold_pusch(gNB, pusch_pdu->scid, pusch_pdu->ul_dmrs_scrambling_id);
}
if (pusch_pdu->transform_precoding == transformPrecoder_disabled) {
// Note: pilot returned by the following function is already the complex conjugate of the transmitted DMRS
nr_pusch_dmrs_rx(gNB,
Ns,
gNB->nr_gold_pusch_dmrs[pusch_pdu->scid][Ns][symbol],
pilot,
(1000 + p),
0,
nb_rb_pusch,
(pusch_pdu->bwp_start + pusch_pdu->rb_start) * NR_NB_SC_PER_RB,
pusch_pdu->dmrs_config_type);
} else { // if transform precoding or SC-FDMA is enabled in Uplink
// NR_SC_FDMA supports type1 DMRS so only 6 DMRS REs per RB possible
const int index = get_index_for_dmrs_lowpapr_seq(nb_rb_pusch * (NR_NB_SC_PER_RB / 2));
const uint8_t u = pusch_pdu->dfts_ofdm.low_papr_group_number;
const uint8_t v = pusch_pdu->dfts_ofdm.low_papr_sequence_number;
c16_t *dmrs_seq = gNB_dmrs_lowpaprtype1_sequence[u][v][index];
LOG_D(PHY,"Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index);
AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n");
AssertFatal(dmrs_seq != NULL, "DMRS low PAPR seq not found, check if DMRS sequences are generated");
nr_pusch_lowpaprtype1_dmrs_rx(gNB, Ns, dmrs_seq, pilot, 1000, 0, nb_rb_pusch, 0, pusch_pdu->dmrs_config_type);
#ifdef DEBUG_PUSCH
printf ("NR_UL_CHANNEL_EST: index %d, u %d,v %d\n", index, u, v);
LOG_M("gNb_DMRS_SEQ.m","gNb_DMRS_SEQ", dmrs_seq,6*nb_rb_pusch,1,1);
#endif
}
//------------------------------------------------//
#ifdef DEBUG_PUSCH
for (int i = 0; i < (6 * nb_rb_pusch); i++) {
LOG_I(PHY, "In %s: %d + j*(%d)\n", __FUNCTION__, pilot[i].r,pilot[i].i);
}
#endif
int nest_count = 0;
uint64_t noise_amp2 = 0;
c16_t ul_ls_est[symbolSize] __attribute__((aligned(32)));
memset(ul_ls_est, 0, sizeof(c16_t) * symbolSize);
delay_t *delay = &gNB->ulsch[ul_id].delay;
memset(delay, 0, sizeof(*delay));
//Initializing the structure before going through the loop
puschAntennaProc_t *rdata = (puschAntennaProc_t *)malloc(
sizeof(puschAntennaProc_t) + symbolSize * sizeof(c16_t)
);
if (!rdata) {
perror("Failed to allocate memory");
return -1;
}
for (int aarx=0; aarx<gNB->frame_parms.nb_antennas_rx; aarx++) {
// Local init in the current loop
rdata->aarx = aarx;
rdata->nest_count = nest_count;
rdata->noise_amp2 = noise_amp2;
rdata->ul_ls_est = ul_ls_est;
rdata->delay = delay;
rdata->gNB = gNB;
rdata->nb_antennas_rx = gNB->frame_parms.nb_antennas_rx
rdata->symbol_offset = symbol_offset;
rtada->ul_ch_estimates = ul_ch_estimates;
rdata->nl = nl;
rdata->ch_offset = ch_offset;
rdata->symbolSize = symbolSize;
rdata->pusch_pdu = pusch_pdu;
rdata->chest_freq = chest_freq;
rdata->pilot = pilot;
rdata->k0 = k0;
rdata->nb_rb_pusch = nb_rb_pusch;
rdata->p = p;
rdata->soffset = soffset;
rdata->max_ch = max_ch;
rdata->pusch_vars = pusch_vars;
rdata->nushift = nushift;
// Call the inner_channel_estimation function
int result = inner_channel_estimation(rdata);
// value update of rdata to be passed to the next inner call
max_ch = rdata->max_ch; // Placeholder for max channel value update
noise_amp2 = rdata->noise_amp2; // Placeholder for noise amplitude squared update
delay->est_delay = rdata->delay->est_delay; // Placeholder for estimated delay update
nest_count = rdata->nest_count; // Placeholder for nested count update
ul_ls_est = rdata->ul_ls_est;
}
// Free the allocated memory
free(rdata);
#ifdef DEBUG_CH
fclose(debug_ch_est);
#endif
if (nvar && nest_count > 0) {
*nvar = (uint32_t)(noise_amp2 / nest_count);
}
return 0;
}
/*******************************************************************
*
* NAME : nr_pusch_ptrs_processing
*
* PARAMETERS : gNB : gNB data structure
* rel15_ul : UL parameters
* UE_id : UE ID
* nr_tti_rx : slot rx TTI
* dmrs_symbol_flag: DMRS Symbol Flag
* symbol : OFDM Symbol
* nb_re_pusch : PUSCH RE's
* nb_re_pusch : PUSCH RE's
*
* RETURN : nothing
*
* DESCRIPTION :
* If ptrs is enabled process the symbol accordingly
* 1) Estimate phase noise per PTRS symbol
* 2) Interpolate PTRS estimated value in TD after all PTRS symbols
* 3) Compensated DMRS based estimated signal with PTRS estimation for slot
*********************************************************************/
// #define DEBUG_UL_PTRS
void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB,
NR_DL_FRAME_PARMS *frame_parms,
nfapi_nr_pusch_pdu_t *rel15_ul,
uint8_t ulsch_id,
uint8_t nr_tti_rx,
unsigned char symbol,
uint32_t nb_re_pusch)
{
NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ulsch_id];
int32_t *ptrs_re_symbol = NULL;
int8_t ret = 0;
uint8_t symbInSlot = rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols;
uint8_t *startSymbIndex = &rel15_ul->start_symbol_index;
uint8_t *nbSymb = &rel15_ul->nr_of_symbols;
uint8_t *L_ptrs = &rel15_ul->pusch_ptrs.ptrs_time_density;
uint8_t *K_ptrs = &rel15_ul->pusch_ptrs.ptrs_freq_density;
uint16_t *dmrsSymbPos = &rel15_ul->ul_dmrs_symb_pos;
uint16_t *ptrsSymbPos = &pusch_vars->ptrs_symbols;
uint8_t *ptrsSymbIdx = &pusch_vars->ptrs_symbol_index;
uint16_t *nb_rb = &rel15_ul->rb_size;
uint8_t *ptrsReOffset = &rel15_ul->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset;
/* loop over antennas */
for (int aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
c16_t *phase_per_symbol = (c16_t *)pusch_vars->ptrs_phase_per_slot[aarx];
ptrs_re_symbol = &pusch_vars->ptrs_re_per_slot;
*ptrs_re_symbol = 0;
phase_per_symbol[symbol].i = 0;
/* set DMRS estimates to 0 angle with magnitude 1 */
if(is_dmrs_symbol(symbol,*dmrsSymbPos)) {
/* set DMRS real estimation to 32767 */
phase_per_symbol[symbol].r=INT16_MAX; // 32767
#ifdef DEBUG_UL_PTRS
printf("[PHY][PTRS]: DMRS Symbol %d -> %4d + j*%4d\n", symbol, phase_per_symbol[symbol].r,phase_per_symbol[symbol].i);
#endif
}
else {// real ptrs value is set to 0
phase_per_symbol[symbol].r = 0;
}
if(symbol == *startSymbIndex) {
*ptrsSymbPos = 0;
set_ptrs_symb_idx(ptrsSymbPos,
*nbSymb,
*startSymbIndex,
1<< *L_ptrs,
*dmrsSymbPos);
}
/* if not PTRS symbol set current ptrs symbol index to zero*/
*ptrsSymbIdx = 0;
/* Check if current symbol contains PTRS */
if(is_ptrs_symbol(symbol, *ptrsSymbPos)) {
*ptrsSymbIdx = symbol;
/*------------------------------------------------------------------------------------------------------- */
/* 1) Estimate common phase error per PTRS symbol */
/*------------------------------------------------------------------------------------------------------- */
nr_ptrs_cpe_estimation(*K_ptrs,
*ptrsReOffset,
*nb_rb,
rel15_ul->rnti,
nr_tti_rx,
symbol,
frame_parms->ofdm_symbol_size,
(int16_t *)&pusch_vars->rxdataF_comp[aarx][(symbol * nb_re_pusch)],
gNB->nr_gold_pusch_dmrs[rel15_ul->scid][nr_tti_rx][symbol],
(int16_t *)&phase_per_symbol[symbol],
ptrs_re_symbol);
}
/* For last OFDM symbol at each antenna perform interpolation and compensation for the slot*/
if(symbol == (symbInSlot -1)) {
/*------------------------------------------------------------------------------------------------------- */
/* 2) Interpolate PTRS estimated value in TD */
/*------------------------------------------------------------------------------------------------------- */
/* If L-PTRS is > 0 then we need interpolation */
if(*L_ptrs > 0) {
ret = nr_ptrs_process_slot(*dmrsSymbPos, *ptrsSymbPos, (int16_t*)phase_per_symbol, *startSymbIndex, *nbSymb);
if(ret != 0) {
LOG_W(PHY,"[PTRS] Compensation is skipped due to error in PTRS slot processing !!\n");
}
}
/*------------------------------------------------------------------------------------------------------- */
/* 3) Compensated DMRS based estimated signal with PTRS estimation */
/*--------------------------------------------------------------------------------------------------------*/
for(uint8_t i = *startSymbIndex; i < symbInSlot; i++) {
/* DMRS Symbol has 0 phase so no need to rotate the respective symbol */
/* Skip rotation if the slot processing is wrong */
if((!is_dmrs_symbol(i,*dmrsSymbPos)) && (ret == 0)) {
#ifdef DEBUG_UL_PTRS
printf("[PHY][UL][PTRS]: Rotate Symbol %2d with %d + j* %d\n", i, phase_per_symbol[i].r,phase_per_symbol[i].i);
#endif
rotate_cpx_vector((c16_t *)&pusch_vars->rxdataF_comp[aarx][i * nb_re_pusch],
&phase_per_symbol[i],
(c16_t *)&pusch_vars->rxdataF_comp[aarx][i * nb_re_pusch],
((*nb_rb) * NR_NB_SC_PER_RB),
15);
} // if not DMRS Symbol
} // symbol loop
} // last symbol check
} // Antenna loop
}
uint32_t calc_power(const int16_t *x, const uint32_t size) {
int64_t sum_x = 0;
int64_t sum_x2 = 0;
for(int k = 0; k<size; k++) {
sum_x = sum_x + x[k];
sum_x2 = sum_x2 + x[k]*x[k];
}
return sum_x2/size - (sum_x/size)*(sum_x/size);
}
int nr_srs_channel_estimation(
const PHY_VARS_gNB *gNB,
const int frame,
const int slot,
const nfapi_nr_srs_pdu_t *srs_pdu,
const nr_srs_info_t *nr_srs_info,
const c16_t **srs_generated_signal,
int32_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)],
int32_t srs_estimated_channel_freq[][1 << srs_pdu->num_ant_ports]
[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)],
int32_t srs_estimated_channel_time[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size],
int32_t srs_estimated_channel_time_shifted[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size],
int8_t *snr_per_rb,
int8_t *snr)
{
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"Calling %s function\n", __FUNCTION__);
#endif
const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start*NR_NB_SC_PER_RB;
const uint8_t N_ap = 1<<srs_pdu->num_ant_ports;
const uint8_t K_TC = 2<<srs_pdu->comb_size;
const uint16_t m_SRS_b = srs_bandwidth_config[srs_pdu->config_index][srs_pdu->bandwidth_index][0];
const uint16_t M_sc_b_SRS = m_SRS_b * NR_NB_SC_PER_RB/K_TC;
uint8_t fd_cdm = N_ap;
if (N_ap == 4 && ((K_TC == 2 && srs_pdu->cyclic_shift >= 4) || (K_TC == 4 && srs_pdu->cyclic_shift >= 6))) {
fd_cdm = 2;
}
c16_t srs_ls_estimated_channel[frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols)];
uint32_t noise_power_per_rb[srs_pdu->bwp_size];
const uint32_t arr_len = frame_parms->nb_antennas_rx * N_ap * M_sc_b_SRS;
int16_t ch_real[arr_len];
memset(ch_real, 0, arr_len * sizeof(int16_t));
int16_t ch_imag[arr_len];
memset(ch_imag, 0, arr_len * sizeof(int16_t));
int16_t noise_real[arr_len];
memset(noise_real, 0, arr_len * sizeof(int16_t));
int16_t noise_imag[arr_len];
memset(noise_imag, 0, arr_len * sizeof(int16_t));
int16_t ls_estimated[2];
uint8_t mem_offset = ((16 - ((long)&srs_estimated_channel_freq[0][0][subcarrier_offset + nr_srs_info->k_0_p[0][0]])) & 0xF) >> 2; // >> 2 <=> /sizeof(int32_t)
// filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0}
// The End of OFDM symbol corresponds to the position of last 16384 in the filter
// The multadd_real_vector_complex_scalar applies the remaining 8 zeros of filter, therefore, to avoid a buffer overflow,
// we added 8 in the array size
int32_t srs_est[frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols) + mem_offset + 8] __attribute__ ((aligned(32)));
for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) {
for (int p_index = 0; p_index < N_ap; p_index++) {
memset(srs_ls_estimated_channel, 0, frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols)*sizeof(c16_t));
memset(srs_est, 0, (frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols) + mem_offset)*sizeof(int32_t));
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"====================== UE port %d --> gNB Rx antenna %i ======================\n", p_index, ant);
#endif
uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
if (subcarrier>frame_parms->ofdm_symbol_size) {
subcarrier -= frame_parms->ofdm_symbol_size;
}
int16_t *srs_estimated_channel16 = (int16_t *)&srs_est[subcarrier + mem_offset];
for (int k = 0; k < M_sc_b_SRS; k++) {
if (k%fd_cdm==0) {
ls_estimated[0] = 0;
ls_estimated[1] = 0;
uint16_t subcarrier_cdm = subcarrier;
for (int cdm_idx = 0; cdm_idx < fd_cdm; cdm_idx++) {
int16_t generated_real = srs_generated_signal[p_index][subcarrier_cdm].r;
int16_t generated_imag = srs_generated_signal[p_index][subcarrier_cdm].i;
int16_t received_real = ((c16_t*)srs_received_signal[ant])[subcarrier_cdm].r;
int16_t received_imag = ((c16_t*)srs_received_signal[ant])[subcarrier_cdm].i;
// We know that nr_srs_info->srs_generated_signal_bits bits are enough to represent the generated_real and generated_imag.
// So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16 bits.
ls_estimated[0] += (int16_t)(((int32_t)generated_real*received_real + (int32_t)generated_imag*received_imag)>>nr_srs_info->srs_generated_signal_bits);
ls_estimated[1] += (int16_t)(((int32_t)generated_real*received_imag - (int32_t)generated_imag*received_real)>>nr_srs_info->srs_generated_signal_bits);
// Subcarrier increment
subcarrier_cdm += K_TC;
if (subcarrier_cdm >= frame_parms->ofdm_symbol_size) {
subcarrier_cdm=subcarrier_cdm-frame_parms->ofdm_symbol_size;
}
}
}
srs_ls_estimated_channel[subcarrier].r = ls_estimated[0];
srs_ls_estimated_channel[subcarrier].i = ls_estimated[1];
#ifdef SRS_DEBUG
int subcarrier_log = subcarrier-subcarrier_offset;
if(subcarrier_log < 0) {
subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size;
}
if(subcarrier_log%12 == 0) {
LOG_I(NR_PHY,"------------------------------------ %d ------------------------------------\n", subcarrier_log/12);
LOG_I(NR_PHY,"\t __genRe________genIm__|____rxRe_________rxIm__|____lsRe________lsIm_\n");
}
LOG_I(NR_PHY,"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
subcarrier_log,
((c16_t*)srs_generated_signal[p_index])[subcarrier].r, ((c16_t*)srs_generated_signal[p_index])[subcarrier].i,
((c16_t*)srs_received_signal[ant])[subcarrier].r, ((c16_t*)srs_received_signal[ant])[subcarrier].i,
ls_estimated[0], ls_estimated[1]);
#endif
const uint16_t sc_offset = subcarrier + mem_offset;
// Channel interpolation
if(srs_pdu->comb_size == 0) {
if(k == 0) { // First subcarrier case
// filt8_start is {12288,8192,4096,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt8_start, ls_estimated, srs_estimated_channel16, 8);
} else if(subcarrier < K_TC) { // Start of OFDM symbol case
// filt8_start is {12288,8192,4096,0,0,0,0,0}
srs_estimated_channel16 = (int16_t *)&srs_est[subcarrier];
const short *filter = mem_offset == 0 ? filt8_start : filt8_start_shift2;
multadd_real_vector_complex_scalar(filter, ls_estimated, srs_estimated_channel16, 8);
} else if((subcarrier+K_TC)>=frame_parms->ofdm_symbol_size || k == (M_sc_b_SRS-1)) { // End of OFDM symbol or last subcarrier cases
// filt8_end is {4096,8192,12288,16384,0,0,0,0}
const short *filter = mem_offset == 0 || k == (M_sc_b_SRS - 1) ? filt8_end : filt8_end_shift2;
multadd_real_vector_complex_scalar(filter, ls_estimated, srs_estimated_channel16, 8);
} else if(k%2 == 1) { // 1st middle case
// filt8_middle2 is {4096,8192,8192,8192,4096,0,0,0}
multadd_real_vector_complex_scalar(filt8_middle2, ls_estimated, srs_estimated_channel16, 8);
} else if(k%2 == 0) { // 2nd middle case
// filt8_middle4 is {0,0,4096,8192,8192,8192,4096,0}
multadd_real_vector_complex_scalar(filt8_middle4, ls_estimated, srs_estimated_channel16, 8);
srs_estimated_channel16 = (int16_t *)&srs_est[sc_offset];
}
} else {
if(k == 0) { // First subcarrier case
// filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt16_start, ls_estimated, srs_estimated_channel16, 16);
} else if(subcarrier < K_TC) { // Start of OFDM symbol case
srs_estimated_channel16 = (int16_t *)&srs_est[sc_offset];
// filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt16_start, ls_estimated, srs_estimated_channel16, 16);
} else if((subcarrier+K_TC)>=frame_parms->ofdm_symbol_size || k == (M_sc_b_SRS-1)) { // End of OFDM symbol or last subcarrier cases
// filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt16_end, ls_estimated, srs_estimated_channel16, 16);
} else { // Middle case
// filt16_middle4 is {4096,8192,8192,8192,8192,8192,8192,8192,4096,0,0,0,0,0,0,0}
multadd_real_vector_complex_scalar(filt16_middle4, ls_estimated, srs_estimated_channel16, 16);
srs_estimated_channel16 = (int16_t *)&srs_est[sc_offset];
}
}
// Subcarrier increment
subcarrier += K_TC;
if (subcarrier >= frame_parms->ofdm_symbol_size) {
subcarrier=subcarrier-frame_parms->ofdm_symbol_size;
}
} // for (int k = 0; k < M_sc_b_SRS; k++)
memcpy(&srs_estimated_channel_freq[ant][p_index][0],
&srs_est[mem_offset],
(frame_parms->ofdm_symbol_size*(1<<srs_pdu->num_symbols))*sizeof(int32_t));
// Compute noise
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
if (subcarrier>frame_parms->ofdm_symbol_size) {
subcarrier -= frame_parms->ofdm_symbol_size;
}
uint16_t base_idx = ant*N_ap*M_sc_b_SRS + p_index*M_sc_b_SRS;
for (int k = 0; k < M_sc_b_SRS; k++) {
ch_real[base_idx+k] = ((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].r;
ch_imag[base_idx+k] = ((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].i;
noise_real[base_idx+k] = abs(srs_ls_estimated_channel[subcarrier].r - ch_real[base_idx+k]);
noise_imag[base_idx+k] = abs(srs_ls_estimated_channel[subcarrier].i - ch_imag[base_idx+k]);
subcarrier += K_TC;
if (subcarrier >= frame_parms->ofdm_symbol_size) {
subcarrier=subcarrier-frame_parms->ofdm_symbol_size;
}
}
#ifdef SRS_DEBUG
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
if (subcarrier>frame_parms->ofdm_symbol_size) {
subcarrier -= frame_parms->ofdm_symbol_size;
}
for (int k = 0; k < K_TC*M_sc_b_SRS; k++) {
int subcarrier_log = subcarrier-subcarrier_offset;
if(subcarrier_log < 0) {
subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size;
}
if(subcarrier_log%12 == 0) {
LOG_I(NR_PHY,"------------------------------------- %d -------------------------------------\n", subcarrier_log/12);
LOG_I(NR_PHY,"\t __lsRe__________lsIm__|____intRe_______intIm__|____noiRe_______noiIm__\n");
}
LOG_I(NR_PHY,"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
subcarrier_log,
srs_ls_estimated_channel[subcarrier].r,
srs_ls_estimated_channel[subcarrier].i,
((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].r,
((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].i,
noise_real[base_idx+(k/K_TC)], noise_imag[base_idx+(k/K_TC)]);
// Subcarrier increment
subcarrier++;
if (subcarrier >= frame_parms->ofdm_symbol_size) {
subcarrier=subcarrier-frame_parms->ofdm_symbol_size;
}
}
#endif
// Convert to time domain
freq2time(gNB->frame_parms.ofdm_symbol_size,
(int16_t*) srs_estimated_channel_freq[ant][p_index],
(int16_t*) srs_estimated_channel_time[ant][p_index]);
memcpy(&srs_estimated_channel_time_shifted[ant][p_index][0],
&srs_estimated_channel_time[ant][p_index][gNB->frame_parms.ofdm_symbol_size>>1],
(gNB->frame_parms.ofdm_symbol_size>>1)*sizeof(int32_t));
memcpy(&srs_estimated_channel_time_shifted[ant][p_index][gNB->frame_parms.ofdm_symbol_size>>1],
&srs_estimated_channel_time[ant][p_index][0],
(gNB->frame_parms.ofdm_symbol_size>>1)*sizeof(int32_t));
} // for (int p_index = 0; p_index < N_ap; p_index++)
} // for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++)
// Compute signal power
uint32_t signal_power = calc_power(ch_real, arr_len) + calc_power(ch_imag, arr_len);
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"signal_power = %u\n", signal_power);
#endif
if (signal_power == 0) {
LOG_W(NR_PHY, "Received SRS signal power is 0\n");
return -1;
}
// Compute noise power
const uint8_t signal_power_bits = log2_approx(signal_power);
const uint8_t factor_bits = signal_power_bits < 32 ? 32 - signal_power_bits : 0; // 32 due to input of dB_fixed(uint32_t x)
const int32_t factor_dB = dB_fixed(1<<factor_bits);
const uint8_t srs_symbols_per_rb = srs_pdu->comb_size == 0 ? 6 : 3;
const uint8_t n_noise_est = frame_parms->nb_antennas_rx*N_ap*srs_symbols_per_rb;
uint64_t sum_re = 0;
uint64_t sum_re2 = 0;
uint64_t sum_im = 0;
uint64_t sum_im2 = 0;
for (int rb = 0; rb < m_SRS_b; rb++) {
sum_re = 0;
sum_re2 = 0;
sum_im = 0;
sum_im2 = 0;
for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) {
for (int p_index = 0; p_index < N_ap; p_index++) {
uint16_t base_idx = ant*N_ap*M_sc_b_SRS + p_index*M_sc_b_SRS + rb*srs_symbols_per_rb;
for (int srs_symb = 0; srs_symb < srs_symbols_per_rb; srs_symb++) {
sum_re = sum_re + noise_real[base_idx+srs_symb];
sum_re2 = sum_re2 + noise_real[base_idx+srs_symb]*noise_real[base_idx+srs_symb];
sum_im = sum_im + noise_imag[base_idx+srs_symb];
sum_im2 = sum_im2 + noise_imag[base_idx+srs_symb]*noise_imag[base_idx+srs_symb];
} // for (int srs_symb = 0; srs_symb < srs_symbols_per_rb; srs_symb++)
} // for (int p_index = 0; p_index < N_ap; p_index++)
} // for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++)
noise_power_per_rb[rb] = max(sum_re2 / n_noise_est - (sum_re / n_noise_est) * (sum_re / n_noise_est) +
sum_im2 / n_noise_est - (sum_im / n_noise_est) * (sum_im / n_noise_est), 1);
snr_per_rb[rb] = dB_fixed((int32_t)((signal_power<<factor_bits)/noise_power_per_rb[rb])) - factor_dB;
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"noise_power_per_rb[%i] = %i, snr_per_rb[%i] = %i dB\n", rb, noise_power_per_rb[rb], rb, snr_per_rb[rb]);
#endif
} // for (int rb = 0; rb < m_SRS_b; rb++)
const uint32_t noise_power = max(calc_power(noise_real, arr_len) + calc_power(noise_imag, arr_len), 1);
*snr = dB_fixed((int32_t)((signal_power<<factor_bits)/(noise_power))) - factor_dB;
#ifdef SRS_DEBUG
LOG_I(NR_PHY,"noise_power = %u, SNR = %i dB\n", noise_power, *snr);
#endif
return 0;
}
\ No newline at end of file
......@@ -757,6 +757,30 @@ typedef struct ulAntennaProc_s {
int numAntennas;
} ulAntennaProc_t;
typedef struct {
PHY_VARS_gNB *gNB;
int aarx;
const int symbol_offset;
c16_t **ul_ch_estimates;
int nl;
int ch_offset;
const int symbolSize;
nfapi_nr_pusch_pdu_t *pusch_pdu;
const int chest_freq;
c16_t pilot[3280] __attribute__((aligned(32)));
const int k0;
const int nb_rb_pusch;
unsigned short p;
const int soffset;
int *max_ch;
c16_t ul_ls_est[symbolSize];
NR_gNB_PUSCH *pusch_vars;
delay_t *delay;
uint64_t noise_amp2;
int nest_count;
const int nushift;
} puschAntennaProc_t;
struct puschSymbolReqId {
uint16_t ulsch_id;
uint16_t frame;
......
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file PHY/defs_gNB.h
\brief Top-level defines and structure definitions for gNB
\author Guy De Souza
\date 2018
\version 0.1
\company Eurecom
\email: desouza@eurecom.fr
\note
\warning
*/
#ifndef __PHY_DEFS_GNB__H__
#define __PHY_DEFS_GNB__H__
#include "defs_nr_common.h"
#include "CODING/nrPolar_tools/nr_polar_pbch_defs.h"
#include "openair2/NR_PHY_INTERFACE/NR_IF_Module.h"
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
#include "PHY/impl_defs_top.h"
#include "PHY/defs_common.h"
#include "PHY/CODING/nrLDPC_extern.h"
#include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h"
#include "executables/rt_profiling.h"
#include "nfapi_nr_interface_scf.h"
#define MAX_NUM_RU_PER_gNB 8
#define MAX_PUCCH0_NID 8
typedef struct {
int nb_id;
int Nid[MAX_PUCCH0_NID];
int lut[MAX_PUCCH0_NID][160][14];
} NR_gNB_PUCCH0_LUT_t;
typedef struct {
uint32_t pbch_a;
uint32_t pbch_a_interleaved;
uint32_t pbch_a_prime;
uint32_t pbch_e[NR_POLAR_PBCH_E_DWORD];
} NR_gNB_PBCH;
typedef enum {
NR_SCH_IDLE,
NR_ACTIVE,
NR_CBA_ACTIVE,
NR_DISABLED
} NR_SCH_status_t;
typedef struct {
/// Nfapi DLSCH PDU
nfapi_nr_dl_tti_pdsch_pdu pdsch_pdu;
/// pointer to pdu from MAC interface (this is "a" in 36.212)
uint8_t *pdu;
/// Pointer to the payload
uint8_t *b;
/// Pointers to transport block segments
uint8_t **c;
/// Frame where current HARQ round was sent
uint32_t frame;
/// Subframe where current HARQ round was sent
uint32_t subframe;
/// Interleaver outputs
uint8_t *f;
/// LDPC lifting size
uint32_t Z;
/// REs unavailable for DLSCH (overlapping with PTRS, CSIRS etc.)
uint32_t unav_res;
} NR_DL_gNB_HARQ_t;
typedef struct {
uint8_t active;
nfapi_nr_dl_tti_csi_rs_pdu csirs_pdu;
} NR_gNB_CSIRS_t;
typedef struct {
int dump_frame;
int round_trials[8];
int total_bytes_tx;
int total_bytes_rx;
int current_Qm;
int current_RI;
int power[MAX_ANT];
int noise_power[MAX_ANT];
int DTX;
int sync_pos;
} NR_gNB_SCH_STATS_t;
typedef struct {
int pucch0_sr_trials;
int pucch0_sr_thres;
int current_pucch0_sr_stat0;
int current_pucch0_sr_stat1;
int pucch0_positive_SR;
int pucch01_trials;
int pucch0_n00;
int pucch0_n01;
int pucch0_thres;
int current_pucch0_stat0;
int current_pucch0_stat1;
int pucch01_DTX;
int pucch02_trials;
int pucch02_DTX;
int pucch2_trials;
int pucch2_DTX;
} NR_gNB_UCI_STATS_t;
typedef struct {
int frame;
uint16_t rnti;
bool active;
/// statistics for DLSCH measurement collection
NR_gNB_SCH_STATS_t dlsch_stats;
/// statistics for ULSCH measurement collection
NR_gNB_SCH_STATS_t ulsch_stats;
NR_gNB_UCI_STATS_t uci_stats;
} NR_gNB_PHY_STATS_t;
typedef struct {
/// Pointers to variables related to DLSCH harq process
NR_DL_gNB_HARQ_t harq_process;
/// beamforming weights for UE-spec transmission (antenna ports 5 or 7..14), for each codeword, maximum 4 layers?
int32_t ***ue_spec_bf_weights;
/// Active flag for baseband transmitter processing
uint8_t active;
/// Number of soft channel bits
uint32_t G;
} NR_gNB_DLSCH_t;
typedef struct {
bool active;
nfapi_nr_dl_tti_ssb_pdu ssb_pdu;
} NR_gNB_SSB_t;
typedef struct {
int frame;
int slot;
nfapi_nr_prach_pdu_t pdu;
} gNB_PRACH_list_t;
#define NUMBER_OF_NR_PRACH_MAX 8
typedef struct {
/// \brief ?.
/// first index: ? [0..1023] (hard coded)
int16_t *prachF;
/// \brief ?.
/// second index: rx antenna [0..63] (hard coded) \note Hard coded array size indexed by \c nb_antennas_rx.
/// third index: frequency-domain sample [0..ofdm_symbol_size*12[
int16_t **rxsigF;
/// \brief local buffer to compute prach_ifft
int32_t *prach_ifft;
gNB_PRACH_list_t list[NUMBER_OF_NR_PRACH_MAX];
} NR_gNB_PRACH;
typedef struct {
uint8_t NumPRSResources;
prs_config_t prs_cfg[NR_MAX_PRS_RESOURCES_PER_SET];
} NR_gNB_PRS;
typedef struct {
/// Nfapi ULSCH PDU
nfapi_nr_pusch_pdu_t ulsch_pdu;
/// Index of current HARQ round for this DLSCH
uint8_t round;
bool new_rx;
/////////////////////// ulsch decoding ///////////////////////
/// flag used to clear d properly (together with d_to_be_cleared below)
/// set to true in nr_fill_ulsch() when new_data_indicator is received
bool harq_to_be_cleared;
/// Transport block size (This is A from 38.212 V15.4.0 section 5.1)
uint32_t TBS;
/// Pointer to the payload (38.212 V15.4.0 section 5.1)
uint8_t *b;
/// Pointers to code blocks after code block segmentation and CRC attachment (38.212 V15.4.0 section 5.2.2)
uint8_t **c;
/// Number of bits in each code block (38.212 V15.4.0 section 5.2.2)
uint32_t K;
/// Number of "Filler" bits added in the code block segmentation (38.212 V15.4.0 section 5.2.2)
uint32_t F;
/// Number of code blocks after code block segmentation (38.212 V15.4.0 section 5.2.2)
uint32_t C;
/// Pointers to code blocks after LDPC coding (38.212 V15.4.0 section 5.3.2)
int16_t **d;
/// flag used to clear d properly (together with harq_to_be_cleared above)
/// set to true in nr_ulsch_decoding() when harq_to_be_cleared is true
/// when true, clear d in the next call to function nr_rate_matching_ldpc_rx()
bool *d_to_be_cleared;
/// LDPC lifting size (38.212 V15.4.0 table 5.3.2-1)
uint32_t Z;
/// Number of bits in each code block after rate matching for LDPC code (38.212 V15.4.0 section 5.4.2.1)
uint32_t E;
/// Number of segments processed so far
uint32_t processedSegments;
decode_abort_t abort_decode;
/// Last index of LLR buffer that contains information.
/// Used for computing LDPC decoder R
int llrLen;
//////////////////////////////////////////////////////////////
} NR_UL_gNB_HARQ_t;
static inline int lenWithCrc(int nbSeg, int len)
{
if (nbSeg > 1)
return (len + 24 + 24 * nbSeg) / nbSeg;
return len + (len > NR_MAX_PDSCH_TBS ? 24 : 16);
}
static inline int crcType(int nbSeg, int len)
{
if (nbSeg > 1)
return CRC24_B;
return len > NR_MAX_PDSCH_TBS ? CRC24_A : CRC16;
}
typedef struct {
//! estimated rssi (dBm)
int rx_rssi_dBm;
//! estimated correlation (wideband linear) between spatial channels (computed in dlsch_demodulation)
int rx_correlation[2];
//! estimated correlation (wideband dB) between spatial channels (computed in dlsch_demodulation)
int rx_correlation_dB[2];
/// Wideband CQI (= SINR)
int wideband_cqi[MAX_NUM_RU_PER_gNB];
/// Wideband CQI in dB (= SINR dB)
int wideband_cqi_dB[MAX_NUM_RU_PER_gNB];
/// Wideband CQI (sum of all RX antennas, in dB)
char wideband_cqi_tot;
/// Subband CQI per RX antenna and RB (= SINR)
int subband_cqi[MAX_NUM_RU_PER_gNB][275];
/// Total Subband CQI and RB (= SINR)
int subband_cqi_tot[275];
/// Subband CQI in dB and RB (= SINR dB)
int subband_cqi_dB[MAX_NUM_RU_PER_gNB][275];
/// Total Subband CQI and RB
int subband_cqi_tot_dB[275];
} ulsch_measurements_gNB;
typedef struct {
uint32_t frame;
uint32_t slot;
uint32_t unav_res;
/// Pointers to 16 HARQ processes for the ULSCH
NR_UL_gNB_HARQ_t *harq_process;
/// HARQ process mask, indicates which processes are currently active
int harq_pid;
/// Allocated RNTI for this ULSCH
uint16_t rnti;
/// Maximum number of LDPC iterations
uint8_t max_ldpc_iterations;
/// number of iterations used in last LDPC decoding
uint8_t last_iteration_cnt;
/// Status Flag indicating for this ULSCH
bool active;
/// Flag to indicate that the UL configuration has been handled. Used to remove a stale ULSCH when frame wraps around
uint8_t handled;
delay_t delay;
ulsch_measurements_gNB ulsch_measurements;
} NR_gNB_ULSCH_t;
typedef struct {
uint8_t active;
/// Frame where current PUCCH pdu was sent
uint32_t frame;
/// Slot where current PUCCH pdu was sent
uint32_t slot;
/// ULSCH PDU
nfapi_nr_pucch_pdu_t pucch_pdu;
} NR_gNB_PUCCH_t;
typedef struct {
uint8_t active;
/// Frame where current SRS pdu was received
uint32_t frame;
/// Slot where current SRS pdu was received
uint32_t slot;
/// ULSCH PDU
nfapi_nr_srs_pdu_t srs_pdu;
} NR_gNB_SRS_t;
typedef struct {
/// \brief Pointers (dynamic) to the received data in the frequency domain.
/// - first index: rx antenna [0..nb_antennas_rx[
/// - second index: ? [0..2*ofdm_symbol_size*frame_parms->symbols_per_tti[
c16_t **rxdataF;
/// \brief holds the transmit data in the frequency domain.
/// For IFFT_FPGA this points to the same memory as PHY_vars->rx_vars[a].RX_DMA_BUFFER. //?
/// - first index: eNB id [0..2] (hard coded)
/// - second index: tx antenna [0..14[ where 14 is the total supported antenna ports.
/// - third index: sample [0..samples_per_frame_woCP]
c16_t **txdataF;
/// \brief Anaglogue beam ID for each OFDM symbol (used when beamforming not done in RU)
/// - first index: antenna port
/// - second index: beam_id [0.. symbols_per_frame[
uint8_t **beam_id;
int32_t *debugBuff;
int32_t debugBuff_sample_offset;
} NR_gNB_COMMON;
typedef struct {
/// \brief Holds the received data in the frequency domain for the allocated RBs in repeated format.
/// - first index: rx antenna id [0..nb_antennas_rx[
/// - second index: ? [0..2*ofdm_symbol_size[
int32_t **rxdataF_ext;
/// \brief Hold the channel estimates in time domain based on DRS.
/// - first index: rx antenna id [0..nb_antennas_rx[
/// - second index: ? [0..4*ofdm_symbol_size[
int32_t **ul_ch_estimates_time;
/// \brief Hold the channel estimates in frequency domain based on DRS.
/// - first index: rx antenna id [0..nb_antennas_rx[
/// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[
int32_t **ul_ch_estimates;
/// \brief Uplink channel estimates extracted in PRBS.
/// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
/// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[
int32_t **ul_ch_estimates_ext;
/// \brief Holds the compensated signal.
/// - first index: rx antenna id [0..nb_antennas_rx[
/// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[
int32_t **rxdataF_comp;
/// \f$\log_2(\max|H_i|^2)\f$
int16_t log2_maxh;
/// measured RX power based on DRS
int ulsch_power[8];
/// total signal over antennas
int ulsch_power_tot;
/// measured RX noise power
int ulsch_noise_power[8];
/// total noise over antennas
int ulsch_noise_power_tot;
/// \brief llr values.
/// - first index: ? [0..1179743] (hard coded)
int16_t *llr;
/// \brief llr values per layer.
/// - first index: ? [0..3] (hard coded)
/// - first index: ? [0..1179743] (hard coded)
int16_t **llr_layers;
/// DMRS symbol index, to be updated every DMRS symbol within a slot.
uint8_t dmrs_symbol;
// PTRS symbol index, to be updated every PTRS symbol within a slot.
uint8_t ptrs_symbol_index;
/// bit mask of PT-RS ofdm symbol indicies
uint16_t ptrs_symbols;
// PTRS subcarriers per OFDM symbol
int32_t ptrs_re_per_slot;
/// \brief Estimated phase error based upon PTRS on each symbol .
/// - first index: ? [0..7] Number of Antenna
/// - second index: ? [0...14] smybol per slot
int32_t **ptrs_phase_per_slot;
/// \brief Total RE count after DMRS/PTRS RE's are extracted from respective symbol.
/// - first index: ? [0...14] smybol per slot
int16_t *ul_valid_re_per_slot;
/// \brief offset for llr corresponding to each symbol
int llr_offset[14];
/// flag to indicate DTX on reception
int DTX;
} NR_gNB_PUSCH;
/// Context data structure for RX/TX portion of slot processing
typedef struct {
/// Component Carrier index
uint8_t CC_id;
/// timestamp transmitted to HW
openair0_timestamp timestamp_tx;
/// slot to act upon for transmission
int slot_tx;
/// slot to act upon for reception
int slot_rx;
/// frame to act upon for transmission
int frame_tx;
/// frame to act upon for reception
int frame_rx;
/// \brief Instance count for RXn-TXnp4 processing thread.
/// \internal This variable is protected by \ref mutex_rxtx.
int instance_cnt;
/// pthread structure for RXn-TXnp4 processing thread
pthread_t pthread;
/// pthread attributes for RXn-TXnp4 processing thread
pthread_attr_t attr;
/// condition variable for tx processing thread
pthread_cond_t cond;
/// mutex for RXn-TXnp4 processing thread
pthread_mutex_t mutex;
/// scheduling parameters for RXn-TXnp4 thread
struct sched_param sched_param_rxtx;
/// \internal This variable is protected by \ref mutex_RUs_tx.
int instance_cnt_RUs;
/// condition variable for tx processing thread
pthread_cond_t cond_RUs;
/// mutex for L1 RXTX processing thread
pthread_mutex_t mutex_RUs;
/// mutex for L1 TX FH synchronization
pthread_mutex_t mutex_RUs_tx;
} gNB_L1_rxtx_proc_t;
/// Context data structure for eNB slot processing
typedef struct gNB_L1_proc_t_s {
/// Component Carrier index
uint8_t CC_id;
/// thread index
int thread_index;
/// timestamp received from HW
openair0_timestamp timestamp_rx;
/// timestamp to send to "slave rru"
openair0_timestamp timestamp_tx;
/// slot to act upon for reception
int slot_rx;
/// slot to act upon for PRACH
int slot_prach;
/// frame to act upon for reception
int frame_rx;
/// frame to act upon for transmission
int frame_tx;
/// frame to act upon for PRACH
int frame_prach;
/// \internal This variable is protected by \ref mutex_td.
int instance_cnt_td;
/// \internal This variable is protected by \ref mutex_te.
int instance_cnt_te;
/// \internal This variable is protected by \ref mutex_prach.
int instance_cnt_prach;
/// \internal This variable is protected by \ref mutex_asynch_rxtx.
int instance_cnt_asynch_rxtx;
/// pthread structure for eNB single processing thread
pthread_t pthread_single;
/// pthread structure for asychronous RX/TX processing thread
pthread_t pthread_asynch_rxtx;
/// pthread structure for dumping L1 stats
pthread_t L1_stats_thread;
/// pthread structure for printing time meas
pthread_t process_stats_thread;
/// pthread structure for reordering L1 tx thread messages
pthread_t pthread_tx_reorder;
/// flag to indicate first RX acquisition
int first_rx;
/// flag to indicate first TX transmission
int first_tx;
/// pthread attributes for single gNB processing thread
pthread_attr_t attr_single;
/// pthread attributes for prach processing thread
pthread_attr_t attr_prach;
/// pthread attributes for asynchronous RX thread
pthread_attr_t attr_asynch_rxtx;
/// scheduling parameters for parallel turbo-decoder thread
struct sched_param sched_param_td;
/// scheduling parameters for parallel turbo-encoder thread
struct sched_param sched_param_te;
/// scheduling parameters for single eNB thread
struct sched_param sched_param_single;
/// scheduling parameters for prach thread
struct sched_param sched_param_prach;
/// scheduling parameters for asynch_rxtx thread
struct sched_param sched_param_asynch_rxtx;
pthread_cond_t cond_prach;
/// condition variable for asynch RX/TX thread
pthread_cond_t cond_asynch_rxtx;
/// mutex for parallel turbo-decoder thread
pthread_mutex_t mutex_td;
/// mutex for parallel turbo-encoder thread
pthread_mutex_t mutex_te;
/// mutex for PRACH thread
pthread_mutex_t mutex_prach;
/// mutex for asynch RX/TX thread
pthread_mutex_t mutex_asynch_rxtx;
/// mutex for RU access to eNB processing (PDSCH/PUSCH)
pthread_mutex_t mutex_RU;
/// mutex for RU_tx access to eNB_tx processing (PDSCH/PUSCH)
pthread_mutex_t mutex_RU_tx;
/// mutex for RU access to eNB processing (PRACH)
pthread_mutex_t mutex_RU_PRACH;
/// mutex for RU access to eNB processing (PRACH BR)
pthread_mutex_t mutex_RU_PRACH_br;
/// mask for RUs serving eNB (PDSCH/PUSCH)
int RU_mask, RU_mask_tx;
/// mask for RUs serving eNB (PRACH)
int RU_mask_prach;
/// set of scheduling variables RXn-TXnp4 threads
gNB_L1_rxtx_proc_t L1_proc, L1_proc_tx;
} gNB_L1_proc_t;
typedef struct {
// common measurements
//! estimated noise power (linear)
unsigned int n0_power[MAX_NUM_RU_PER_gNB];
//! estimated noise power (dB)
unsigned int n0_power_dB[MAX_NUM_RU_PER_gNB];
//! total estimated noise power (linear)
unsigned int n0_power_tot;
//! estimated avg noise power (dB)
unsigned int n0_power_tot_dB;
//! estimated avg noise power per RB per RX ant (lin)
fourDimArray_t *n0_subband_power;
//! estimated avg noise power per RB per RX ant (dB)
fourDimArray_t *n0_subband_power_dB;
//! estimated avg subband noise power (dB)
unsigned int n0_subband_power_avg_dB;
//! estimated avg subband noise power per antenna (dB)
unsigned int n0_subband_power_avg_perANT_dB[MAX_ANT];
//! estimated avg noise power per RB (dB)
int n0_subband_power_tot_dB[275];
//! estimated avg noise power per RB (dBm)
int n0_subband_power_tot_dBm[275];
/// PRACH background noise level
int prach_I0;
} PHY_MEASUREMENTS_gNB;
#define MAX_NUM_NR_RX_RACH_PDUS 4
#define MAX_UL_PDUS_PER_SLOT 8
#define MAX_NUM_NR_SRS_PDUS 8
// the current RRC resource allocation is that each UE gets its
// "own" PUCCH resource (for F0) in a dedicated PRB in each slot
// therefore, we can have up to "number of UE" UCI PDUs
#define MAX_NUM_NR_UCI_PDUS MAX_MOBILES_PER_GNB
/// Top-level PHY Data Structure for gNB
typedef struct PHY_VARS_gNB_s {
/// Module ID indicator for this instance
module_id_t Mod_id;
uint8_t CC_id;
uint8_t configured;
gNB_L1_proc_t proc;
int single_thread_flag;
int abstraction_flag;
int num_RU;
RU_t *RU_list[MAX_NUM_RU_PER_gNB];
/// Ethernet parameters for northbound midhaul interface
eth_params_t eth_params_n;
/// Ethernet parameters for fronthaul interface
eth_params_t eth_params;
int rx_total_gain_dB;
int (*nr_start_if)(struct RU_t_s *ru, struct PHY_VARS_gNB_s *gNB);
uint8_t local_flag;
nfapi_nr_config_request_scf_t gNB_config;
NR_DL_FRAME_PARMS frame_parms;
PHY_MEASUREMENTS_gNB measurements;
NR_IF_Module_t *if_inst;
NR_UL_IND_t UL_INFO;
/// NFAPI RX ULSCH information
nfapi_nr_rx_data_pdu_t rx_pdu_list[MAX_UL_PDUS_PER_SLOT];
/// NFAPI RX ULSCH CRC information
nfapi_nr_crc_t crc_pdu_list[MAX_UL_PDUS_PER_SLOT];
/// NFAPI SRS information
nfapi_nr_srs_indication_pdu_t srs_pdu_list[MAX_NUM_NR_SRS_PDUS];
/// NFAPI UCI information
nfapi_nr_uci_t uci_pdu_list[MAX_NUM_NR_UCI_PDUS];
/// NFAPI PRACH information
nfapi_nr_prach_indication_pdu_t prach_pdu_indication_list[MAX_NUM_NR_RX_RACH_PDUS];
nfapi_nr_ul_tti_request_t UL_tti_req;
nfapi_nr_uci_indication_t uci_indication;
int max_nb_pucch;
int max_nb_srs;
int max_nb_pdsch;
int max_nb_pusch;
NR_gNB_PBCH pbch;
NR_gNB_COMMON common_vars;
NR_gNB_PRACH prach_vars;
NR_gNB_PRS prs_vars;
NR_gNB_PUSCH *pusch_vars;
NR_gNB_PUCCH_t *pucch;
NR_gNB_SRS_t *srs;
NR_gNB_ULSCH_t *ulsch;
NR_gNB_PHY_STATS_t phy_stats[MAX_MOBILES_PER_GNB];
t_nrPolar_params **polarParams;
/// SRS variables
nr_srs_info_t **nr_srs_info;
/// CSI variables
nr_csi_info_t *nr_csi_info;
// reference amplitude for TX
int16_t TX_AMP;
// flag to activate 3GPP phase symbolwise rotation
bool phase_comp;
// PUCCH0 Look-up table for cyclic-shifts
NR_gNB_PUCCH0_LUT_t pucch0_lut;
/// PBCH DMRS sequence
uint32_t nr_gold_pbch_dmrs[2][64][NR_PBCH_DMRS_LENGTH_DWORD];
/// PBCH interleaver
uint8_t nr_pbch_interleaver[NR_POLAR_PBCH_PAYLOAD_BITS];
/// PDCCH DMRS sequence
uint32_t ***nr_gold_pdcch_dmrs;
/// PDSCH DMRS sequence
uint32_t ****nr_gold_pdsch_dmrs;
/// PUSCH DMRS
uint32_t ****nr_gold_pusch_dmrs;
// Mask of occupied RBs, per symbol and PRB
uint32_t rb_mask_ul[14][9];
/// PRS sequence
uint32_t ****nr_gold_prs;
/// PRACH root sequence
c16_t X_u[64][839];
/// OFDM symbol offset divisor for UL
uint32_t ofdm_offset_divisor;
int ldpc_offload_flag;
int max_ldpc_iterations;
/// indicate the channel estimation technique in time domain
int chest_time;
/// indicate the channel estimation technique in freq domain
int chest_freq;
/// counter to average prach energh over first 100 prach opportunities
int prach_energy_counter;
int pdcch_gold_init;
int pdsch_gold_init[2];
int pusch_gold_init[2];
int ap_N1;
int ap_N2;
int ap_XP;
int pucch0_thres;
int pusch_thres;
int prach_thres;
int srs_thres;
uint64_t bad_pucch;
int num_ulprbbl;
int ulprbbl[275];
/*
time_stats_t phy_proc;
*/
time_stats_t phy_proc_tx;
time_stats_t phy_proc_rx;
time_stats_t rx_prach;
/*
time_stats_t ofdm_mod_stats;
*/
time_stats_t dlsch_encoding_stats;
time_stats_t dlsch_modulation_stats;
time_stats_t dlsch_scrambling_stats;
time_stats_t dlsch_resource_mapping_stats;
time_stats_t dlsch_layer_mapping_stats;
time_stats_t dlsch_precoding_stats;
time_stats_t tinput;
time_stats_t tprep;
time_stats_t tparity;
time_stats_t toutput;
time_stats_t dlsch_rate_matching_stats;
time_stats_t dlsch_interleaving_stats;
time_stats_t dlsch_segmentation_stats;
time_stats_t rx_pusch_stats;
time_stats_t rx_pusch_init_stats;
time_stats_t rx_pusch_symbol_processing_stats;
time_stats_t ul_indication_stats;
time_stats_t slot_indication_stats;
time_stats_t schedule_response_stats;
time_stats_t ulsch_ldpc_decoding_stats;
time_stats_t ulsch_deinterleaving_stats;
time_stats_t ulsch_channel_estimation_stats;
time_stats_t ulsch_llr_stats;
time_stats_t rx_srs_stats;
time_stats_t generate_srs_stats;
time_stats_t get_srs_signal_stats;
time_stats_t srs_channel_estimation_stats;
time_stats_t srs_timing_advance_stats;
time_stats_t srs_report_tlv_stats;
time_stats_t srs_beam_report_stats;
time_stats_t srs_iq_matrix_stats;
/*
time_stats_t rx_dft_stats;
time_stats_t ulsch_freq_offset_estimation_stats;
*/
notifiedFIFO_t respPuschSymb;
notifiedFIFO_t respDecode;
notifiedFIFO_t resp_L1;
notifiedFIFO_t L1_tx_free;
notifiedFIFO_t L1_tx_filled;
notifiedFIFO_t L1_tx_out;
notifiedFIFO_t L1_rx_out;
notifiedFIFO_t resp_RU_tx;
tpool_t threadPool;
int nbSymb;
int num_pusch_symbols_per_thread;
int dmrs_num_antennas_per_thread;
pthread_t L1_rx_thread;
int L1_rx_thread_core;
pthread_t L1_tx_thread;
int L1_tx_thread_core;
struct processingData_L1tx *msgDataTx;
void *scopeData;
/// structure for analyzing high-level RT measurements
rt_L1_profiling_t rt_L1_profiling;
} PHY_VARS_gNB;
typedef struct puschSymbolProc_s {
PHY_VARS_gNB *gNB;
NR_DL_FRAME_PARMS *frame_parms;
nfapi_nr_pusch_pdu_t *rel15_ul;
int ulsch_id;
int slot;
int startSymbol;
int numSymbols;
int16_t *llr;
int16_t **llr_layers;
int16_t *s;
uint32_t nvar;
} puschSymbolProc_t;
typedef struct ulAntennaProc_s {
PHY_VARS_gNB *gNB;
unsigned char Ns;
int nl;
unsigned short p;
unsigned char symbol;
int ul_id;
unsigned short bwp_start_subcarrier;
nfapi_nr_pusch_pdu_t *pusch_pdu;
int *max_ch;
uint32_t *nvar;
int numAntennas;
} ulAntennaProc_t;
typedef struct {
PHY_VARS_gNB *gNB;
int aarx;
const int symbol_offset;
c16_t **ul_ch_estimates;
int nl;
int ch_offset;
const int symbolSize;
nfapi_nr_pusch_pdu_t *pusch_pdu;
const int chest_freq;
c16_t pilot[3280] __attribute__((aligned(32)));
const int k0;
const int nb_rb_pusch;
unsigned short p;
const int soffset;
int *max_ch;
c16_t ul_ls_est[symbolSize];
NR_gNB_PUSCH *pusch_vars;
delay_t *delay;
uint64_t noise_amp2;
int nest_count;
const int nushift;
} puschAntennaProc_t;
struct puschSymbolReqId {
uint16_t ulsch_id;
uint16_t frame;
uint8_t slot;
uint16_t spare;
} __attribute__((packed));
union puschSymbolReqUnion {
struct puschSymbolReqId s;
uint64_t p;
};
typedef struct LDPCDecode_s {
PHY_VARS_gNB *gNB;
NR_UL_gNB_HARQ_t *ulsch_harq;
t_nrLDPC_dec_params decoderParms;
NR_gNB_ULSCH_t *ulsch;
short* ulsch_llr;
int ulsch_id;
int harq_pid;
int rv_index;
int A;
int E;
int Kc;
int Qm;
int Kr_bytes;
int nbSegments;
int segment_r;
int r_offset;
int offset;
int decodeIterations;
uint32_t tbslbrm;
} ldpcDecode_t;
struct ldpcReqId {
uint16_t rnti;
uint16_t frame;
uint8_t subframe;
uint8_t codeblock;
uint16_t spare;
} __attribute__((packed));
union ldpcReqUnion {
struct ldpcReqId s;
uint64_t p;
};
typedef struct processingData_L1 {
int frame_rx;
int slot_rx;
openair0_timestamp timestamp_tx;
PHY_VARS_gNB *gNB;
} processingData_L1_t;
typedef enum {
FILLED,
FILLING,
NOT_FILLED
} msgStatus_t;
typedef struct processingData_L1tx {
int frame;
int slot;
int frame_rx;
int slot_rx;
openair0_timestamp timestamp_tx;
PHY_VARS_gNB *gNB;
nfapi_nr_dl_tti_pdcch_pdu pdcch_pdu[NFAPI_NR_MAX_NB_CORESETS];
nfapi_nr_ul_dci_request_pdus_t ul_pdcch_pdu[NFAPI_NR_MAX_NB_CORESETS];
NR_gNB_CSIRS_t csirs_pdu[NR_SYMBOLS_PER_SLOT];
NR_gNB_DLSCH_t **dlsch;
NR_gNB_SSB_t ssb[64];
uint16_t num_pdsch_slot;
int num_dl_pdcch;
int num_ul_pdcch;
/* a reference to the sched_response, to release it when not needed anymore */
int sched_response_id;
} processingData_L1tx_t;
typedef struct processingData_L1rx {
int frame_rx;
int slot_rx;
PHY_VARS_gNB *gNB;
} processingData_L1rx_t;
#endif
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