diff --git a/ci-scripts/conf_files/nrue.uicc.conf b/ci-scripts/conf_files/nrue.uicc.conf index 7e74382580..d473deb693 100644 --- a/ci-scripts/conf_files/nrue.uicc.conf +++ b/ci-scripts/conf_files/nrue.uicc.conf @@ -32,7 +32,7 @@ channelmod = { model_name = "rfsimu_channel_enB0" type = "AWGN"; ploss_dB = 20; - noise_power_dB = -4; + noise_power_dB = -2; forgetfact = 0; offset = 0; ds_tdl = 0; @@ -40,8 +40,8 @@ channelmod = { { # UL, modify on gNB side model_name = "rfsimu_channel_ue0" type = "AWGN"; - ploss_dB = 20; - noise_power_dB = -2; + ploss_dB = 0; + noise_power_dB = -100; forgetfact = 0; offset = 0; ds_tdl = 0; diff --git a/common/platform_constants.h b/common/platform_constants.h index 2faadc3dcd..2add8e984a 100644 --- a/common/platform_constants.h +++ b/common/platform_constants.h @@ -83,7 +83,7 @@ #define MAX_NUM_SLICES 1024 // RLC Entity -#define RLC_TX_MAXSIZE 10000000 +#define RLC_TX_MAXSIZE 50000 #define RLC_RX_MAXSIZE 10000000 #define SEND_MRW_ON 240 #define MAX_ANT 8 diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index c6524630f9..2447106289 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -143,13 +143,15 @@ static void nr_hermitian_eigenvalues(const int N, float A_re[4][4], float A_im[4 float cos_phi = re_pq / mag; float sin_phi = im_pq / mag; - // Multiply column q by e^{-j*phi} and row q by e^{+j*phi} + // Similarity transformation D^H A D with D=diag(1,..,e^{-jphi},..,1) + // Column q: A[k][q] *= e^{-jphi} for k != q (diagonal unchanged) for (int k = 0; k < N; k++) { if (k == q) continue; float old_re = A_re[k][q], old_im = A_im[k][q]; A_re[k][q] = old_re * cos_phi + old_im * sin_phi; A_im[k][q] = -old_re * sin_phi + old_im * cos_phi; } + // Row q from Hermitian symmetry: A[q][k] = conj(A[k][q]) for (int k = 0; k < N; k++) { if (k == q) continue; @@ -564,6 +566,7 @@ int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue, c16_t csi_rs_estimated_conjch_ch[frame_parms->nb_antennas_rx][N_ports][frame_parms->nb_antennas_rx][N_ports] [frame_parms->ofdm_symbol_size + FILTER_MARGIN] __attribute__((aligned(32))); int32_t csi_rs_estimated_A_MF[N_ports][N_ports][frame_parms->ofdm_symbol_size + FILTER_MARGIN] __attribute__((aligned(32))); + memset(csi_rs_estimated_A_MF, 0, sizeof(csi_rs_estimated_A_MF)); // Arrays only needed for the 2x2 fast path int32_t csi_rs_estimated_A_MF_sq[N_ports][N_ports][frame_parms->ofdm_symbol_size + FILTER_MARGIN] __attribute__((aligned(32))); @@ -689,6 +692,7 @@ int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue, } } + #ifdef NR_CSIRS_DEBUG LOG_I(NR_PHY, "(%i) sc %d eigenvalues: %.1f %.1f %.1f %.1f\n", k, sc_idx, eig[0], eig[1], eig[2], eig[3]); @@ -980,6 +984,151 @@ int nr_csi_rs_pmi_estimation(const PHY_VARS_NR_UE *ue, if (best_sinr > 0) *precoded_sinr_dB = dB_fixed((best_sinr / 2) / interference_plus_noise_power); + } else if (rank_indicator == 2) { + // Rank 3: three-layer precoder using beam pairs (TS 38.214 Table 5.2.2.2.1-5) + // W(l,n) = 1/(2*sqrt(3)) * [v_a v_a v_b; phi_n*v_a -phi_n*v_a phi_n*v_b] + // where v_a = [1; w1_{2l}], v_b = [1; -w1_{2l}] (orthogonal beam pair) + // i1[0] = l in {0,...,N1*O1/2-1} = {0,1,2,3}, i2[0] = n in {0,1} + // Layer 0: A + phi*B, Layer 1: A - phi*B, Layer 2: A' + phi*B' + // where A = h0 + w1*h1, B = h2 + w1*h3, A' = h0 - w1*h1, B' = h2 - w1*h3 + int64_t best_sinr = -1; + uint8_t best_l = 0, best_n = 0; + const int N_beam_pairs = 4; // N1*O1/2 + + for (int l = 0; l < N_beam_pairs; l++) { + int beam_a = 2 * l; // first beam index in DFT grid + int64_t power[2] = {0}; + + for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb + csirs_config_pdu->nr_of_rbs); rb++) { + if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) + continue; + uint16_t k = (frame_parms->first_carrier_offset + rb * NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; + uint16_t k_offset = k + mem_offset; + + for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) { + const c16_t h0 = csi_rs_estimated_channel_freq[ant_rx][0][k_offset]; + const c16_t h1 = csi_rs_estimated_channel_freq[ant_rx][1][k_offset]; + const c16_t h2 = csi_rs_estimated_channel_freq[ant_rx][2][k_offset]; + const c16_t h3 = csi_rs_estimated_channel_freq[ant_rx][3][k_offset]; + + float w1r = w1_re[beam_a], w1i = w1_im[beam_a]; + + // A = h0 + w1*h1 (beam a, ports 0-1) + float A_re = (float)h0.r + w1r * h1.r - w1i * h1.i; + float A_im = (float)h0.i + w1r * h1.i + w1i * h1.r; + // B = h2 + w1*h3 (beam a, ports 2-3) + float B_re = (float)h2.r + w1r * h3.r - w1i * h3.i; + float B_im = (float)h2.i + w1r * h3.i + w1i * h3.r; + // A' = h0 - w1*h1 (beam b, ports 0-1) + float Ap_re = (float)h0.r - w1r * h1.r + w1i * h1.i; + float Ap_im = (float)h0.i - w1r * h1.i - w1i * h1.r; + // B' = h2 - w1*h3 (beam b, ports 2-3) + float Bp_re = (float)h2.r - w1r * h3.r + w1i * h3.i; + float Bp_im = (float)h2.i - w1r * h3.i - w1i * h3.r; + + for (int n = 0; n < 2; n++) { + // Layer 0: A + phi_n * B + float l0_re = A_re + w2_re[n] * B_re - w2_im[n] * B_im; + float l0_im = A_im + w2_re[n] * B_im + w2_im[n] * B_re; + // Layer 1: A - phi_n * B + float l1_re = A_re - w2_re[n] * B_re + w2_im[n] * B_im; + float l1_im = A_im - w2_re[n] * B_im - w2_im[n] * B_re; + // Layer 2: A' + phi_n * B' + float l2_re = Ap_re + w2_re[n] * Bp_re - w2_im[n] * Bp_im; + float l2_im = Ap_im + w2_re[n] * Bp_im + w2_im[n] * Bp_re; + + power[n] += (int64_t)(l0_re * l0_re + l0_im * l0_im + + l1_re * l1_re + l1_im * l1_im + + l2_re * l2_re + l2_im * l2_im); + } + } + } + + for (int n = 0; n < 2; n++) { + if (power[n] > best_sinr) { + best_sinr = power[n]; + best_l = l; + best_n = n; + } + } + } + + i1[0] = best_l; + i1[1] = 0; + i1[2] = 0; + i2[0] = best_n; + if (best_sinr > 0) + *precoded_sinr_dB = dB_fixed((best_sinr / 3) / interference_plus_noise_power); + + } else if (rank_indicator == 3) { + // Rank 4: four-layer precoder using beam pairs (TS 38.214 Table 5.2.2.2.1-5) + // W(l,n) = 1/4 * [v_a v_a v_b v_b; phi_n*v_a -phi_n*v_a phi_n*v_b -phi_n*v_b] + // Layer 0: A + phi*B, Layer 1: A - phi*B, Layer 2: A' + phi*B', Layer 3: A' - phi*B' + int64_t best_sinr = -1; + uint8_t best_l = 0, best_n = 0; + const int N_beam_pairs = 4; + + for (int l = 0; l < N_beam_pairs; l++) { + int beam_a = 2 * l; + int64_t power[2] = {0}; + + for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb + csirs_config_pdu->nr_of_rbs); rb++) { + if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) + continue; + uint16_t k = (frame_parms->first_carrier_offset + rb * NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; + uint16_t k_offset = k + mem_offset; + + for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) { + const c16_t h0 = csi_rs_estimated_channel_freq[ant_rx][0][k_offset]; + const c16_t h1 = csi_rs_estimated_channel_freq[ant_rx][1][k_offset]; + const c16_t h2 = csi_rs_estimated_channel_freq[ant_rx][2][k_offset]; + const c16_t h3 = csi_rs_estimated_channel_freq[ant_rx][3][k_offset]; + + float w1r = w1_re[beam_a], w1i = w1_im[beam_a]; + + float A_re = (float)h0.r + w1r * h1.r - w1i * h1.i; + float A_im = (float)h0.i + w1r * h1.i + w1i * h1.r; + float B_re = (float)h2.r + w1r * h3.r - w1i * h3.i; + float B_im = (float)h2.i + w1r * h3.i + w1i * h3.r; + float Ap_re = (float)h0.r - w1r * h1.r + w1i * h1.i; + float Ap_im = (float)h0.i - w1r * h1.i - w1i * h1.r; + float Bp_re = (float)h2.r - w1r * h3.r + w1i * h3.i; + float Bp_im = (float)h2.i - w1r * h3.i - w1i * h3.r; + + for (int n = 0; n < 2; n++) { + float l0_re = A_re + w2_re[n] * B_re - w2_im[n] * B_im; + float l0_im = A_im + w2_re[n] * B_im + w2_im[n] * B_re; + float l1_re = A_re - w2_re[n] * B_re + w2_im[n] * B_im; + float l1_im = A_im - w2_re[n] * B_im - w2_im[n] * B_re; + float l2_re = Ap_re + w2_re[n] * Bp_re - w2_im[n] * Bp_im; + float l2_im = Ap_im + w2_re[n] * Bp_im + w2_im[n] * Bp_re; + float l3_re = Ap_re - w2_re[n] * Bp_re + w2_im[n] * Bp_im; + float l3_im = Ap_im - w2_re[n] * Bp_im - w2_im[n] * Bp_re; + + power[n] += (int64_t)(l0_re * l0_re + l0_im * l0_im + + l1_re * l1_re + l1_im * l1_im + + l2_re * l2_re + l2_im * l2_im + + l3_re * l3_re + l3_im * l3_im); + } + } + } + + for (int n = 0; n < 2; n++) { + if (power[n] > best_sinr) { + best_sinr = power[n]; + best_l = l; + best_n = n; + } + } + } + + i1[0] = best_l; + i1[1] = 0; + i1[2] = 0; + i2[0] = best_n; + if (best_sinr > 0) + *precoded_sinr_dB = dB_fixed((best_sinr / 4) / interference_plus_noise_power); + } else { // RI=3 or RI=4: Use identity-like precoder (i1=0, i2=0) // Compute SINR from per-layer effective channel power with identity precoding diff --git a/tools/scripts/traffic_runner.sh b/tools/scripts/traffic_runner.sh index bf7f0c06ca..6d525f4042 100755 --- a/tools/scripts/traffic_runner.sh +++ b/tools/scripts/traffic_runner.sh @@ -10,14 +10,16 @@ set -euo pipefail PROFILE="${PROFILE:-}" # Fixed server coordinates -IPERF_HOST_UDP="192.168.71.129" +IPERF_HOST_UDP="192.168.71.130" IPERF_HOST_TCP="192.168.71.130" -IPERF_PORT_UDP=5201 -IPERF_PORT_TCP=5202 OAITUN_IP="$(ip -o -4 addr show dev oaitun_ue1 | awk '{print $4}' | cut -d/ -f1)" +# Per-UE port: derive from last octet of oaitun IP (12.1.1.x → port 5200+x) +UE_OCTET="${OAITUN_IP##*.}" +IPERF_PORT=$((5200 + UE_OCTET)) + # Very long duration to approximate "forever" -LONG_T="${LONG_T:-31536000}" # 1 year in seconds +LONG_T="${LONG_T:-86400}" # 24h (iperf3 max) # -------------- args -------------- if [[ $# -gt 0 ]]; then @@ -33,15 +35,17 @@ fi [[ -n "$PROFILE" ]] || { echo "ERROR: --profile is required" >&2; exit 2; } -iperf_tcp_dl_forever() { ( iperf -c "$IPERF_HOST_TCP" -B "$OAITUN_IP" -p "$IPERF_PORT_TCP" -R -t "$LONG_T" >/dev/null 2>&1 ); } -iperf_tcp_ul_forever() { ( iperf -c "$IPERF_HOST_TCP" -B "$OAITUN_IP" -p "$IPERF_PORT_TCP" -t "$LONG_T" >/dev/null 2>&1 ); } -# iperf_udp_dl_forever() { ( nohup iperf -u -c "$IPERF_HOST_UDP" -B "$OAITUN_IP" -p "$IPERF_PORT_UDP" -R -t "$LONG_T" >/dev/null 2>&1 ); } -iperf_udp_dl_forever() { ( iperf -u -c "$IPERF_HOST_UDP" -B "$OAITUN_IP" -p "$IPERF_PORT_UDP" -R -b $1 -t "$LONG_T" >/dev/null 2>&1 ); } -iperf_udp_ul_forever() { ( iperf -u -c "$IPERF_HOST_UDP" -B "$OAITUN_IP" -p "$IPERF_PORT_UDP" -b $1 -t "$LONG_T" >/dev/null 2>&1 ); } +iperf_tcp_dl_forever() { ( iperf -c "$IPERF_HOST_TCP" -B "$OAITUN_IP" -p "$IPERF_PORT" -R -t "$LONG_T" >/dev/null 2>&1 ); } +iperf_tcp_ul_forever() { ( iperf -c "$IPERF_HOST_TCP" -B "$OAITUN_IP" -p "$IPERF_PORT" -t "$LONG_T" >/dev/null 2>&1 ); } +# Use iperf3 for UDP DL — iperf2 -R does not properly pass -b bandwidth to server +iperf_udp_dl_forever() { ( iperf3 -u -c "$IPERF_HOST_UDP" -B "$OAITUN_IP" -p "$IPERF_PORT" -R -b $1 -t "$LONG_T" >/dev/null 2>&1 ); } +iperf_udp_ul_forever() { ( iperf3 -u -c "$IPERF_HOST_UDP" -B "$OAITUN_IP" -p "$IPERF_PORT" -b $1 -t "$LONG_T" >/dev/null 2>&1 ); } +iperf_tcp_dl_parallel_forever() { ( iperf -c "$IPERF_HOST_TCP" -B "$OAITUN_IP" -p "$IPERF_PORT" -R -w 10M -P 8 -t "$LONG_T" >/dev/null 2>&1 ); } # ---------------- profiles ---------------- do_boring() { - iperf_udp_dl_forever 1M + # iperf_tcp_dl_parallel_forever + iperf_udp_dl_forever 8M wait # iperf -c "$IPERF_HOST" -p "$IPERF_PORT" -B "$OAITUN_IP" -u -b 25M -t "$LONG_T" }