ch_awgn: Improve API

The API of functions srsran_ch_awgn_X was causing confusion between
noise variance and standard deviation. Also, in the complex-valued case,
the noise variance did not take into account the fact that the signal is
two-dimensional.

All uses of these functions are modified accordingly.
This commit is contained in:
dvdgrgrtt 2021-12-14 15:12:35 +01:00 committed by dvdgrgrtt
parent 7dc2313957
commit a69fb1d50f
14 changed files with 64 additions and 55 deletions

View File

@ -683,10 +683,9 @@ int main(int argc, char** argv)
// find the noise spectral density // find the noise spectral density
float snr_lin = srsran_convert_dB_to_power(file_snr); float snr_lin = srsran_convert_dB_to_power(file_snr);
float n0 = abs_avg / snr_lin; float n0 = abs_avg / snr_lin;
float nstd = sqrtf(n0 / 2);
// add some noise to the signal // add some noise to the signal
srsran_ch_awgn_c(output_buffer, output_buffer, nstd, sf_n_samples); srsran_ch_awgn_c(output_buffer, output_buffer, n0, sf_n_samples);
} }
/* send to file or usrp */ /* send to file or usrp */

View File

@ -992,7 +992,7 @@ int main(int argc, char** argv)
if (!null_file_sink) { if (!null_file_sink) {
/* Apply AWGN */ /* Apply AWGN */
if (output_file_snr != +INFINITY) { if (output_file_snr != +INFINITY) {
float var = srsran_convert_dB_to_amplitude(-(output_file_snr + 3.0f)); float var = srsran_convert_dB_to_power(-output_file_snr);
for (int k = 0; k < cell.nof_ports; k++) { for (int k = 0; k < cell.nof_ports; k++) {
srsran_ch_awgn_c(output_buffer[k], output_buffer[k], var, sf_n_samples); srsran_ch_awgn_c(output_buffer[k], output_buffer[k], var, sf_n_samples);
} }

View File

@ -1,23 +1,15 @@
/** /**
* \file ch_awgn.h
* \brief Additive white Gaussian noise channel object
* *
* \section COPYRIGHT * \copyright Copyright 2013-2021 Software Radio Systems Limited
* *
* Copyright 2013-2021 Software Radio Systems Limited * \copyright By using this file, you agree to the terms and conditions set
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of * forth in the LICENSE file which can be found at the top level of
* the distribution. * the distribution.
* *
*/ */
/**********************************************************************************************
* File: ch_awgn.h
*
* Description: Additive white gaussian noise channel object
*
* Reference:
*********************************************************************************************/
#include "srsran/config.h" #include "srsran/config.h"
#include <stdint.h> #include <stdint.h>
@ -29,7 +21,7 @@ extern "C" {
#endif #endif
/** /**
* The srsRAN channel AWGN implements an efficient Box-Muller Method accelerated with SIMD. * \brief srsRAN channel AWGN implements an efficient Box-Muller Method accelerated with SIMD.
*/ */
typedef struct { typedef struct {
float* table_cos; float* table_cos;
@ -39,7 +31,7 @@ typedef struct {
} srsran_channel_awgn_t; } srsran_channel_awgn_t;
/** /**
* Initialization function of the channel AWGN object * \brief function of the channel AWGN object
* *
* @param q AWGN channel object * @param q AWGN channel object
* @param seed random generator seed * @param seed random generator seed
@ -47,7 +39,7 @@ typedef struct {
SRSRAN_API int srsran_channel_awgn_init(srsran_channel_awgn_t* q, uint32_t seed); SRSRAN_API int srsran_channel_awgn_init(srsran_channel_awgn_t* q, uint32_t seed);
/** /**
* Sets the noise level N0 in decibels full scale (dBfs) * \brief the noise level N0 in decibels full scale (dBfs)
* *
* @param q AWGN channel object * @param q AWGN channel object
* @param n0_dBfs noise level * @param n0_dBfs noise level
@ -55,7 +47,7 @@ SRSRAN_API int srsran_channel_awgn_init(srsran_channel_awgn_t* q, uint32_t seed)
SRSRAN_API int srsran_channel_awgn_set_n0(srsran_channel_awgn_t* q, float n0_dBfs); SRSRAN_API int srsran_channel_awgn_set_n0(srsran_channel_awgn_t* q, float n0_dBfs);
/** /**
* Runs the complex AWGN channel * \brief the complex AWGN channel
* *
* @param q AWGN channel object * @param q AWGN channel object
* @param in complex input array * @param in complex input array
@ -65,7 +57,7 @@ SRSRAN_API int srsran_channel_awgn_set_n0(srsran_channel_awgn_t* q, float n0_dBf
SRSRAN_API void srsran_channel_awgn_run_c(srsran_channel_awgn_t* q, const cf_t* in, cf_t* out, uint32_t length); SRSRAN_API void srsran_channel_awgn_run_c(srsran_channel_awgn_t* q, const cf_t* in, cf_t* out, uint32_t length);
/** /**
* Runs the real AWGN channel * \brief the real AWGN channel
* *
* @param q AWGN channel object * @param q AWGN channel object
* @param in real input array * @param in real input array
@ -75,15 +67,31 @@ SRSRAN_API void srsran_channel_awgn_run_c(srsran_channel_awgn_t* q, const cf_t*
SRSRAN_API void srsran_channel_awgn_run_f(srsran_channel_awgn_t* q, const float* in, float* out, uint32_t length); SRSRAN_API void srsran_channel_awgn_run_f(srsran_channel_awgn_t* q, const float* in, float* out, uint32_t length);
/** /**
* Free AWGN channel generator data * \brief AWGN channel generator data
* *
* @param q AWGN channel object * @param q AWGN channel object
*/ */
SRSRAN_API void srsran_channel_awgn_free(srsran_channel_awgn_t* q); SRSRAN_API void srsran_channel_awgn_free(srsran_channel_awgn_t* q);
/**
* \brief signal \p input with AWGN to obtain signal \p output (complex case).
*
* @param[in] input Input signal
* @param[out] output Output signal
* @param[in] variance Noise variance
* @param[in] len Number of samples
*/
SRSRAN_API void srsran_ch_awgn_c(const cf_t* input, cf_t* output, float variance, uint32_t len); SRSRAN_API void srsran_ch_awgn_c(const cf_t* input, cf_t* output, float variance, uint32_t len);
SRSRAN_API void srsran_ch_awgn_f(const float* x, float* y, float variance, uint32_t len); /**
* \brief Perturb signal \p input with AWGN to obtain signal \p output (real case).
*
* @param[in] input Input signal
* @param[out] output Output signal
* @param[in] variance Noise variance
* @param[in] len Number of samples
*/
SRSRAN_API void srsran_ch_awgn_f(const float* input, float* output, float variance, uint32_t len);
SRSRAN_API float srsran_ch_awgn_get_variance(float ebno_db, float rate); SRSRAN_API float srsran_ch_awgn_get_variance(float ebno_db, float rate);

View File

@ -169,7 +169,7 @@ int main(int argc, char** argv)
if (have_channel) { if (have_channel) {
// Add noise // Add noise
float std_dev = srsran_convert_dB_to_amplitude(-(snr_db + 3.0f)) * 0.1f; float std_dev = srsran_convert_dB_to_power(-(snr_db + 20.0f));
srsran_ch_awgn_c(est.pilot_recv_signal, est.pilot_recv_signal, std_dev, SRSRAN_REFSIGNAL_MAX_NUM_SF(1)); srsran_ch_awgn_c(est.pilot_recv_signal, est.pilot_recv_signal, std_dev, SRSRAN_REFSIGNAL_MAX_NUM_SF(1));
} }

View File

@ -119,7 +119,6 @@ static inline void channel_awgn_run(srsran_channel_awgn_t* q, const float* in, f
#if SRSRAN_SIMD_F_SIZE #if SRSRAN_SIMD_F_SIZE
for (; i < (int)size - SRSRAN_SIMD_F_SIZE + 1; i += SRSRAN_SIMD_F_SIZE) { for (; i < (int)size - SRSRAN_SIMD_F_SIZE + 1; i += SRSRAN_SIMD_F_SIZE) {
if (i % AWGN_TABLE_READ_BURST == 0) { if (i % AWGN_TABLE_READ_BURST == 0) {
idx1 = channel_awgn_rand(q); idx1 = channel_awgn_rand(q);
idx2 = channel_awgn_rand(q); idx2 = channel_awgn_rand(q);
@ -145,7 +144,6 @@ static inline void channel_awgn_run(srsran_channel_awgn_t* q, const float* in, f
#endif /* SRSRAN_SIMD_F_SIZE */ #endif /* SRSRAN_SIMD_F_SIZE */
for (; i < size; i++) { for (; i < size; i++) {
if (i % AWGN_TABLE_READ_BURST == 0) { if (i % AWGN_TABLE_READ_BURST == 0) {
idx1 = channel_awgn_rand(q); idx1 = channel_awgn_rand(q);
idx2 = channel_awgn_rand(q); idx2 = channel_awgn_rand(q);
@ -197,19 +195,21 @@ void srsran_ch_awgn_c(const cf_t* x, cf_t* y, float variance, uint32_t len)
{ {
cf_t tmp; cf_t tmp;
uint32_t i; uint32_t i;
float stddev = sqrtf(variance);
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
__real__ tmp = rand_gauss(); __real__ tmp = rand_gauss();
__imag__ tmp = rand_gauss(); __imag__ tmp = rand_gauss();
tmp *= variance; tmp *= stddev * (float)M_SQRT1_2;
y[i] = tmp + x[i]; y[i] = tmp + x[i];
} }
} }
void srsran_ch_awgn_f(const float* x, float* y, float variance, uint32_t len) void srsran_ch_awgn_f(const float* x, float* y, float variance, uint32_t len)
{ {
uint32_t i; uint32_t i;
float stddev = sqrtf(variance);
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
y[i] = x[i] + variance * rand_gauss(); y[i] = x[i] + stddev * rand_gauss();
} }
} }

View File

@ -184,13 +184,13 @@ int main(int argc, char** argv)
for (uint32_t i = 0; i < snr_points; i++) { for (uint32_t i = 0; i < snr_points; i++) {
ebno_db = SNR_MIN + i * ebno_inc; ebno_db = SNR_MIN + i * ebno_inc;
esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f); esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f);
var[i] = srsran_convert_dB_to_amplitude(esno_db); var[i] = srsran_convert_dB_to_power(-esno_db);
varunc[i] = srsran_convert_dB_to_amplitude(ebno_db); varunc[i] = srsran_convert_dB_to_power(-ebno_db);
} }
} else { } else {
esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f); esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f);
var[0] = srsran_convert_dB_to_amplitude(esno_db); var[0] = srsran_convert_dB_to_power(-esno_db);
varunc[0] = srsran_convert_dB_to_amplitude(ebno_db); varunc[0] = srsran_convert_dB_to_power(-ebno_db);
snr_points = 1; snr_points = 1;
} }

View File

@ -314,6 +314,7 @@ int main(int argc, char** argv)
int n_error_words_avx512_flood = 0; int n_error_words_avx512_flood = 0;
#endif // lV_HAVE_AVX512 #endif // lV_HAVE_AVX512
float noise_var = srsran_convert_dB_to_power(-snr);
float noise_std_dev = srsran_convert_dB_to_amplitude(-snr); float noise_std_dev = srsran_convert_dB_to_amplitude(-snr);
int16_t inf15 = (1U << 14U) - 1; int16_t inf15 = (1U << 14U) - 1;
@ -371,12 +372,12 @@ int main(int argc, char** argv)
} }
// Apply AWGN // Apply AWGN
srsran_ch_awgn_f(symbols_rm, symbols_rm, noise_std_dev, batch_size * (rm_length + F)); srsran_ch_awgn_f(symbols_rm, symbols_rm, noise_var, batch_size * (rm_length + F));
// Convert symbols into LLRs // Convert symbols into LLRs
for (i = 0; i < batch_size; i++) { for (i = 0; i < batch_size; i++) {
for (j = 0; j < rm_length + F; j++) { //+F because we have already considered fillerbits when modulating. for (j = 0; j < rm_length + F; j++) { //+F because we have already considered fillerbits when modulating.
symbols[i * finalN + j] = symbols_rm[i * (rm_length + F) + j] * 2 / (noise_std_dev * noise_std_dev); symbols[i * finalN + j] = symbols_rm[i * (rm_length + F) + j] * 2 / noise_var;
} }
// the rest of symbols are undetermined, set LLR to 0 // the rest of symbols are undetermined, set LLR to 0
for (; j < finalN; j++) { for (; j < finalN; j++) {

View File

@ -409,6 +409,7 @@ int main(int argc, char** argv)
int n_error_words_avx512_flood = 0; int n_error_words_avx512_flood = 0;
#endif // LV_HAVE_AVX512 #endif // LV_HAVE_AVX512
float noise_var = srsran_convert_dB_to_power(-snr);
float noise_std_dev = srsran_convert_dB_to_amplitude(-snr); float noise_std_dev = srsran_convert_dB_to_amplitude(-snr);
int16_t inf15 = (1U << 14U) - 1; int16_t inf15 = (1U << 14U) - 1;
@ -478,12 +479,12 @@ int main(int argc, char** argv)
} }
// Apply AWGN // Apply AWGN
srsran_ch_awgn_f(rm_symbols, rm_symbols, noise_std_dev, batch_size * rm_length); srsran_ch_awgn_f(rm_symbols, rm_symbols, noise_var, batch_size * rm_length);
// Convert symbols into LLRs // Convert symbols into LLRs
for (i = 0; i < batch_size; i++) { for (i = 0; i < batch_size; i++) {
for (j = 0; j < rm_length; j++) { for (j = 0; j < rm_length; j++) {
rm_symbols[i * rm_length + j] = rm_symbols[i * rm_length + j] * 2 / (noise_std_dev * noise_std_dev); rm_symbols[i * rm_length + j] = rm_symbols[i * rm_length + j] * 2 / noise_var;
} }
} }

View File

@ -184,9 +184,9 @@ int main(int argc, char** argv)
int j = 0; int j = 0;
int snr_points = 0; int snr_points = 0;
int errors_symb = 0; int errors_symb = 0;
int errors_symb_s = 0; int errors_symb_s = 0;
int errors_symb_c = 0; int errors_symb_c = 0;
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
int errors_symb_c_avx2 = 0; int errors_symb_c_avx2 = 0;
#endif #endif
@ -208,12 +208,12 @@ int main(int argc, char** argv)
double elapsed_time_enc_avx2[SNR_POINTS + 1]; double elapsed_time_enc_avx2[SNR_POINTS + 1];
// 16-bit quantizer // 16-bit quantizer
int16_t inf16 = (1U << 15U) - 1; int16_t inf16 = (1U << 15U) - 1;
int8_t inf8 = (1U << 7U) - 1; int8_t inf8 = (1U << 7U) - 1;
float gain_s = NAN; float gain_s = NAN;
float gain_c = NAN; float gain_c = NAN;
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
float gain_c_avx2 = NAN; float gain_c_avx2 = NAN;
#endif #endif
srsran_polar_code_t code; srsran_polar_code_t code;
@ -319,13 +319,13 @@ int main(int argc, char** argv)
for (int i = 0; i < snr_points; i++) { for (int i = 0; i < snr_points; i++) {
snr_db = SNR_MIN + i * snr_inc; snr_db = SNR_MIN + i * snr_inc;
snr_db_vec[i] = snr_db; snr_db_vec[i] = snr_db;
var[i] = srsran_convert_dB_to_amplitude(-snr_db); var[i] = srsran_convert_dB_to_power(-snr_db);
} }
snr_db_vec[snr_points] = 101; // include the no noise case snr_db_vec[snr_points] = 101; // include the no noise case
snr_points++; snr_points++;
} else { } else {
snr_db_vec[0] = snr_db; snr_db_vec[0] = snr_db;
var[0] = srsran_convert_dB_to_amplitude(-snr_db); var[0] = srsran_convert_dB_to_power(-snr_db);
snr_points = 1; snr_points = 1;
} }

View File

@ -206,11 +206,11 @@ int main(int argc, char** argv)
for (uint32_t i = 0; i < snr_points; i++) { for (uint32_t i = 0; i < snr_points; i++) {
ebno_db = SNR_MIN + i * ebno_inc; ebno_db = SNR_MIN + i * ebno_inc;
esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f); esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f);
var[i] = srsran_convert_dB_to_amplitude(-esno_db); var[i] = srsran_convert_dB_to_power(-esno_db);
} }
} else { } else {
esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f); esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f);
var[0] = srsran_convert_dB_to_amplitude(-esno_db); var[0] = srsran_convert_dB_to_power(-esno_db);
snr_points = 1; snr_points = 1;
} }
for (uint32_t i = 0; i < snr_points; i++) { for (uint32_t i = 0; i < snr_points; i++) {

View File

@ -154,10 +154,10 @@ void populate_channel(srsran_tx_scheme_t type, cf_t* h[SRSRAN_MAX_PORTS][SRSRAN_
static void awgn(cf_t* y[SRSRAN_MAX_PORTS], uint32_t n, float snr) static void awgn(cf_t* y[SRSRAN_MAX_PORTS], uint32_t n, float snr)
{ {
int i; int i;
float std_dev = srsran_convert_dB_to_amplitude(-(snr + 3.0f)) * scaling; float var = srsran_convert_dB_to_power(-snr) * scaling * scaling;
for (i = 0; i < nof_rx_ports; i++) { for (i = 0; i < nof_rx_ports; i++) {
srsran_ch_awgn_c(y[i], y[i], std_dev, n); srsran_ch_awgn_c(y[i], y[i], var, n);
} }
} }

View File

@ -213,8 +213,8 @@ int main(int argc, char** argv)
// add some noise to the signal // add some noise to the signal
if (snr != -1.0) { if (snr != -1.0) {
float nstd = powf(10.0f, -snr / 20.0f); float var = powf(10.0f, -snr / 10.0f);
srsran_ch_awgn_c(buff_ptrs[0], buff_ptrs[0], nstd, nread); srsran_ch_awgn_c(buff_ptrs[0], buff_ptrs[0], var, nread);
} }
// try to decode // try to decode

View File

@ -175,8 +175,8 @@ int main(int argc, char** argv)
if (snr != -1.0) { if (snr != -1.0) {
snr -= 10.0; snr -= 10.0;
printf("Adding AWGN with target SNR: %.2fdB\n", snr); printf("Adding AWGN with target SNR: %.2fdB\n", snr);
float nstd = srsran_convert_dB_to_amplitude(-snr); float var = srsran_convert_dB_to_power(-snr);
srsran_ch_awgn_c(fft_buffer, fft_buffer, nstd, SFLEN); srsran_ch_awgn_c(fft_buffer, fft_buffer, var, SFLEN);
} }
// look for NPSS signal // look for NPSS signal

View File

@ -166,8 +166,8 @@ int main(int argc, char** argv)
// ADD CHANNEL NOISE // ADD CHANNEL NOISE
if (snr < 50) { if (snr < 50) {
float std_dev = powf(10.0f, -(snr + 3.0f) / 20.0f); float var = powf(10.0f, -snr / 10.0f);
srsran_ch_awgn_c(output_buffer, output_buffer, std_dev, output_buffer_len); srsran_ch_awgn_c(output_buffer, output_buffer, var, output_buffer_len);
} }
// ADD FREQUENCY OFFSET // ADD FREQUENCY OFFSET