Files
openairinterface5g/openair1/PHY/TOOLS/signal_energy.c
T
Rakesh Mundlamuri 729dc02b88 Split the code in the SNR loop as functions for readability
- Introduce signal energy and noise variance functions
- Combine rotation and OFDM modulation RX as a function
- Harmonize the use of number of antennas across the code
- Rename nr_ue_pusch_common_procedures() to nr_tx_rotation_and_ofdm_mod() to decribe the functionality better
2026-01-09 16:58:34 +05:30

212 lines
7.2 KiB
C

/*
* 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
*/
#include "tools_defs.h"
#include "PHY/impl_defs_top.h"
// Compute Energy of a complex signal vector, removing the DC component!
// input : points to vector
// length : length of vector in complex samples
#define shift 4
//-----------------------------------------------------------------
// Average Power calculation with DC removing
//-----------------------------------------------------------------
int32_t signal_energy(int32_t *input,uint32_t length)
{
uint32_t i;
int32_t temp;
simde__m128i in, in_clp, i16_min, coe1;
simde__m128 num0, num1, num2, num3, recp1;
//init
num0 = simde_mm_setzero_ps();
num1 = simde_mm_setzero_ps();
i16_min = simde_mm_set1_epi16(SHRT_MIN);
coe1 = simde_mm_set1_epi16(1);
recp1 = simde_mm_rcp_ps(simde_mm_cvtepi32_ps(simde_mm_set1_epi32(length)));
//Acc
for (i = 0; i < (length >> 2); i++) {
in = simde_mm_loadu_si128((simde__m128i *)input);
in_clp = simde_mm_subs_epi16(in, simde_mm_cmpeq_epi16(in, i16_min));//if in=SHRT_MIN in+1, else in
num0 = simde_mm_add_ps(num0, simde_mm_cvtepi32_ps(simde_mm_madd_epi16(in_clp, in_clp)));
num1 = simde_mm_add_ps(num1, simde_mm_cvtepi32_ps(simde_mm_madd_epi16(in, coe1)));//DC
input += 4;
}
//Ave
num2 = simde_mm_dp_ps(num0, recp1, 0xFF);//AC power
num3 = simde_mm_dp_ps(num1, recp1, 0xFF);//DC
num3 = simde_mm_mul_ps(num3, num3); //DC power
//remove DC
temp = simde_mm_cvtsi128_si32(simde_mm_cvttps_epi32(simde_mm_sub_ps(num2, num3)));
return temp;
}
uint32_t signal_energy_nodc(const c16_t *input, uint32_t length)
{
// init
simde__m128 mm0 = simde_mm_setzero_ps();
// Acc
for (int32_t i = 0; i < (length >> 2); i++) {
simde__m128i in = simde_mm_loadu_si128((simde__m128i *)input);
mm0 = simde_mm_add_ps(mm0, simde_mm_cvtepi32_ps(simde_mm_madd_epi16(in, in)));
input += 4;
}
// leftover
float leftover_sum = 0;
c16_t *leftover_input = (c16_t *)input;
uint16_t lefover_count = length - ((length >> 2) << 2);
for (int32_t i = 0; i < lefover_count; i++) {
leftover_sum += leftover_input[i].r * leftover_input[i].r + leftover_input[i].i * leftover_input[i].i;
}
// Ave
float sums[4];
simde_mm_store_ps(sums, mm0);
return (uint32_t)((sums[0] + sums[1] + sums[2] + sums[3] + leftover_sum) / (float)length);
}
double signal_energy_fp(double *s_re[2],double *s_im[2],uint32_t nb_antennas,uint32_t length,uint32_t offset)
{
int32_t aa,i;
double V=0.0;
for (i=0; i<length; i++) {
for (aa=0; aa<nb_antennas; aa++) {
V= V + (s_re[aa][i+offset]*s_re[aa][i+offset]) + (s_im[aa][i+offset]*s_im[aa][i+offset]);
}
}
return(V/length/nb_antennas);
}
double signal_energy_fp2(struct complexd *s,uint32_t length)
{
int32_t i;
double V=0.0;
for (i=0; i<length; i++) {
// printf("signal_energy_fp2 : %f,%f => %f\n",s[i].x,s[i].y,V);
// // V= V + (s[i].y*s[i].x) + (s[i].y*s[i].x);
V= V + (s[i].r*s[i].r) + (s[i].i*s[i].i);
}
return(V/length);
}
int32_t signal_power(int32_t *input, uint32_t length)
{
uint32_t i;
int32_t temp;
simde__m128i in, in_clp, i16_min;
simde__m128 num0, num1;
simde__m128 recp1;
//init
num0 = simde_mm_setzero_ps();
i16_min = simde_mm_set1_epi16(SHRT_MIN);
recp1 = simde_mm_rcp_ps(simde_mm_cvtepi32_ps(simde_mm_set1_epi32(length)));
//Acc
for (i = 0; i < (length >> 2); i++) {
in = simde_mm_loadu_si128((simde__m128i *)input);
in_clp = simde_mm_subs_epi16(in, simde_mm_cmpeq_epi16(in, i16_min));//if in=SHRT_MIN in+1, else in
num0 = simde_mm_add_ps(num0, simde_mm_cvtepi32_ps(simde_mm_madd_epi16(in_clp, in_clp)));
input += 4;
}
//Ave
num1 = simde_mm_dp_ps(num0, recp1, 0xFF);
temp = simde_mm_cvtsi128_si32(simde_mm_cvttps_epi32(num1));
return temp;
}
int32_t interference_power(int32_t *input, uint32_t length)
{
uint32_t i;
int32_t temp;
simde__m128i in, in_clp, i16_min;
simde__m128i num0, num1, num2, num3;
simde__m128 num4, num5, num6;
simde__m128 recp1;
//init
i16_min = simde_mm_set1_epi16(SHRT_MIN);
num5 = simde_mm_setzero_ps();
recp1 = simde_mm_rcp_ps(simde_mm_cvtepi32_ps(simde_mm_set1_epi32(length>>2)));// 1/n, n= length/4
//Acc
for (i = 0; i < (length >> 2); i++) {
in = simde_mm_loadu_si128((simde__m128i *)input);
in_clp = simde_mm_subs_epi16(in, simde_mm_cmpeq_epi16(in, i16_min)); //if in=SHRT_MIN, in+1, else in
num0 = simde_mm_cvtepi16_epi32(in_clp); //lower 2 complex [0], [1]
num1 = simde_mm_cvtepi16_epi32(simde_mm_shuffle_epi32(in_clp, 0x4E)); //upper 2 complex [2], [3]
num2 = simde_mm_srai_epi32(simde_mm_add_epi32(num0, num1), 0x01); //average A=complex( [0] + [2] ) / 2, B=complex( [1] + [3] ) / 2
num3 = simde_mm_sub_epi32(num2, simde_mm_shuffle_epi32(num2, 0x4E)); //complexA-complexB, B-A
num4 = simde_mm_dp_ps(simde_mm_cvtepi32_ps(num3), simde_mm_cvtepi32_ps(num3), 0x3F);//C = num3 lower complex power, C, C, C
num5 = simde_mm_add_ps(num5, num4); //Acc Cn, Cn, Cn, Cn,
input += 4;
}
//Interference ve
num6 = simde_mm_mul_ps(num5, recp1); //Cn / n
temp = simde_mm_cvtsi128_si32(simde_mm_cvttps_epi32(num6));
return temp;
}
// Computes transmitter energy level
double compute_tx_energy_level(c16_t **txdata, int nb_antennas, int offset, int length, int n_trials)
{
double txlev_sum = 0, atxlev[nb_antennas];
for (int aa = 0; aa < nb_antennas; aa++) {
atxlev[aa] = signal_energy((int32_t *)&txdata[aa][offset], length);
txlev_sum += atxlev[aa];
if (n_trials == 1)
printf("txlev[%d] = %f (%f dB) txlev_sum %f\n", aa, atxlev[aa], 10 * log10(atxlev[aa]), txlev_sum);
}
return txlev_sum;
}
// Computes noise variance from the input transmit energy and SNR
double compute_noise_variance(double txlev_sum, uint16_t ofdm_symbol_size, int N_RB, double SNR, int n_trials)
{
double sigma_dB = 10 * log10(txlev_sum * ((double)ofdm_symbol_size / (12 * N_RB))) - SNR;
double sigma = pow(10, sigma_dB / 10);
if (n_trials == 1)
printf("sigma %f (%f dB), txlev_sum %f (factor %f)\n",
sigma,
sigma_dB,
10 * log10(txlev_sum),
(double)(double)ofdm_symbol_size / (12 * N_RB));
return sigma;
}