Commit 2fb541a6 authored by Bartosz Podrygajlo's avatar Bartosz Podrygajlo

Add option to use global noise power for all RX channels in RFSimulator

Added new command line option to channelmod: noise_power_dBFS. This options
allows the user to configure noise power in dBFS added instead of the per-channel
value.

This makes it so noise is not accumulated per channel reaching higher than expected
values.

The dBFS unit allows easy configuration. The gNB by default uses -36 dBFS setting.
To reach 3dB SNR one should set the noise_power_dBFS value to -39.

To configure using command line use --channelmod.noise_power_dBFS -50. Using this
setting the gNB and nrUE connect without issue.
parent 82fbb6bb
...@@ -142,6 +142,7 @@ Channel simulation parameters can also be specified on the command line by using ...@@ -142,6 +142,7 @@ Channel simulation parameters can also be specified on the command line by using
|:--- |:---- |:---- |:----| |:--- |:---- |:---- |:----|
|`modellist` |char string |`DefaultChannelList`|select and load the `modellist` from the config file.| |`modellist` |char string |`DefaultChannelList`|select and load the `modellist` from the config file.|
|`max_chan` |integer |10 |set the maximum number of channel models that can be defined in the system. Must be greater than the number of model definitions in the model list loaded at init time.| |`max_chan` |integer |10 |set the maximum number of channel models that can be defined in the system. Must be greater than the number of model definitions in the model list loaded at init time.|
|`noise_power_dBFS` |integer |0 |Noise power in dBFS. If set, noise per channel is not applied. To achieve positive SNR use values below the default gNB/nrUE amp backoff value (-36dBFS)|
Example usage: Example usage:
```bash ```bash
......
...@@ -73,6 +73,7 @@ static telnetshell_vardef_t channelmod_vardef[] = {{"", 0, 0, NULL}}; ...@@ -73,6 +73,7 @@ static telnetshell_vardef_t channelmod_vardef[] = {{"", 0, 0, NULL}};
static unsigned int max_chan; static unsigned int max_chan;
static channel_desc_t **defined_channels; static channel_desc_t **defined_channels;
static char *modellist_name; static char *modellist_name;
static int noise_power_dBFS = INVALID_DBFS_VALUE;
void fill_channel_desc(channel_desc_t *chan_desc, void fill_channel_desc(channel_desc_t *chan_desc,
uint8_t nb_tx, uint8_t nb_tx,
...@@ -2365,6 +2366,10 @@ int load_channellist(uint8_t nb_tx, uint8_t nb_rx, double sampling_rate, uint64_ ...@@ -2365,6 +2366,10 @@ int load_channellist(uint8_t nb_tx, uint8_t nb_rx, double sampling_rate, uint64_
return channel_list.numelt; return channel_list.numelt;
} /* load_channelist */ } /* load_channelist */
int get_noise_power_dBFS(void) {
return noise_power_dBFS;
}
#ifdef RANDOM_CHANNEL_MAIN #ifdef RANDOM_CHANNEL_MAIN
#define sampling_rate 5.0 #define sampling_rate 5.0
#define Td 2.0 #define Td 2.0
......
...@@ -278,10 +278,15 @@ typedef enum { ...@@ -278,10 +278,15 @@ typedef enum {
#define CHANNELMOD_MODELLIST_PARANAME "modellist" #define CHANNELMOD_MODELLIST_PARANAME "modellist"
#define CHANNELMOD_HELP_MODELLIST "<list name> channel list name in config file describing the model type and its parameters\n" #define CHANNELMOD_HELP_MODELLIST "<list name> channel list name in config file describing the model type and its parameters\n"
#define CHANNELMOD_HELP_NOISE_POWER \
"Noise power in dBFS. If set, noise per channel is not applied. To achieve positive SNR use values below -36dBFS\n"
#define INVALID_DBFS_VALUE 100
// clang-format off // clang-format off
#define CHANNELMOD_PARAMS_DESC { \ #define CHANNELMOD_PARAMS_DESC { \
{"max_chan", "Max number of runtime models", 0, .uptr=&max_chan, .defintval=10, TYPE_UINT, 0}, \ {"max_chan", "Max number of runtime models", 0, .uptr=&max_chan, .defintval=10, TYPE_UINT, 0}, \
{CHANNELMOD_MODELLIST_PARANAME, CHANNELMOD_HELP_MODELLIST, 0, .strptr=&modellist_name, .defstrval="DefaultChannelList", TYPE_STRING, 0}, \ {CHANNELMOD_MODELLIST_PARANAME, CHANNELMOD_HELP_MODELLIST, 0, .strptr=&modellist_name, .defstrval="DefaultChannelList", TYPE_STRING, 0}, \
{"noise_power_dBFS", CHANNELMOD_HELP_NOISE_POWER, 0, .iptr=&noise_power_dBFS, .defintval=INVALID_DBFS_VALUE, TYPE_INT, 0 },\
} }
// clang-format on // clang-format on
...@@ -585,5 +590,6 @@ void do_DL_sig(sim_t *sim, ...@@ -585,5 +590,6 @@ void do_DL_sig(sim_t *sim,
int CC_id); int CC_id);
void do_UL_sig(sim_t *sim, uint16_t subframe, uint8_t abstraction_flag, LTE_DL_FRAME_PARMS *frame_parms, uint32_t frame, int ru_id, uint8_t CC_id, int NB_UEs); void do_UL_sig(sim_t *sim, uint16_t subframe, uint8_t abstraction_flag, LTE_DL_FRAME_PARMS *frame_parms, uint32_t frame, int ru_id, uint8_t CC_id, int NB_UEs);
int get_noise_power_dBFS(void);
#endif #endif
...@@ -42,12 +42,13 @@ ...@@ -42,12 +42,13 @@
legacy: we regenerate each sub frame in UL, and each frame only in DL legacy: we regenerate each sub frame in UL, and each frame only in DL
*/ */
void rxAddInput(const c16_t *input_sig, void rxAddInput(const c16_t *input_sig,
c16_t *after_channel_sig, cf_t *after_channel_sig,
int rxAnt, int rxAnt,
channel_desc_t *channelDesc, channel_desc_t *channelDesc,
int nbSamples, int nbSamples,
uint64_t TS, uint64_t TS,
uint32_t CirSize) uint32_t CirSize,
bool add_noise)
{ {
if ((channelDesc->sat_height > 0) && (channelDesc->enable_dynamic_delay || channelDesc->enable_dynamic_Doppler)) { // model for transparent satellite on circular orbit if ((channelDesc->sat_height > 0) && (channelDesc->enable_dynamic_delay || channelDesc->enable_dynamic_Doppler)) { // model for transparent satellite on circular orbit
/* assumptions: /* assumptions:
...@@ -127,12 +128,12 @@ void rxAddInput(const c16_t *input_sig, ...@@ -127,12 +128,12 @@ void rxAddInput(const c16_t *input_sig,
const double pathLossLinear = pow(10,channelDesc->path_loss_dB/20.0); const double pathLossLinear = pow(10,channelDesc->path_loss_dB/20.0);
// Energy in one sample to calibrate input noise // Energy in one sample to calibrate input noise
// the normalized OAI value seems to be 256 as average amplitude (numerical amplification = 1) // the normalized OAI value seems to be 256 as average amplitude (numerical amplification = 1)
const double noise_per_sample = pow(10,channelDesc->noise_power_dB/10.0) * 256; const double noise_per_sample = add_noise ? pow(10,channelDesc->noise_power_dB/10.0) * 256 : 0;
const uint64_t dd = channelDesc->channel_offset; const uint64_t dd = channelDesc->channel_offset;
const int nbTx=channelDesc->nb_tx; const int nbTx=channelDesc->nb_tx;
for (int i=0; i<nbSamples; i++) { for (int i=0; i<nbSamples; i++) {
struct complex16 *out_ptr=after_channel_sig+i; cf_t *out_ptr = after_channel_sig + i;
struct complexd rx_tmp= {0}; struct complexd rx_tmp= {0};
for (int txAnt=0; txAnt < nbTx; txAnt++) { for (int txAnt=0; txAnt < nbTx; txAnt++) {
...@@ -166,8 +167,8 @@ void rxAddInput(const c16_t *input_sig, ...@@ -166,8 +167,8 @@ void rxAddInput(const c16_t *input_sig,
channelDesc->Doppler_phase_cur[rxAnt] += channelDesc->Doppler_phase_inc; channelDesc->Doppler_phase_cur[rxAnt] += channelDesc->Doppler_phase_inc;
} }
out_ptr->r = lround(rx_tmp.r*pathLossLinear + noise_per_sample*gaussZiggurat(0.0,1.0)); out_ptr->r += rx_tmp.r * pathLossLinear + noise_per_sample * gaussZiggurat(0.0, 1.0);
out_ptr->i = lround(rx_tmp.i*pathLossLinear + noise_per_sample*gaussZiggurat(0.0,1.0)); out_ptr->i += rx_tmp.i * pathLossLinear + noise_per_sample * gaussZiggurat(0.0, 1.0);
out_ptr++; out_ptr++;
} }
......
...@@ -23,13 +23,15 @@ ...@@ -23,13 +23,15 @@
#ifndef __RFSIMULATOR_H #ifndef __RFSIMULATOR_H
#define __RFSIMULATOR_H #define __RFSIMULATOR_H
#include <stdbool.h>
void rxAddInput( const c16_t *input_sig, void rxAddInput( const c16_t *input_sig,
c16_t *after_channel_sig, cf_t *after_channel_sig,
int rxAnt, int rxAnt,
channel_desc_t *channelDesc, channel_desc_t *channelDesc,
int nbSamples, int nbSamples,
uint64_t TS, uint64_t TS,
uint32_t CirSize uint32_t CirSize,
bool apply_noise
); );
#endif #endif
...@@ -1006,7 +1006,9 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest ...@@ -1006,7 +1006,9 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest
// Clear the output buffer // Clear the output buffer
for (int a=0; a<nbAnt; a++) for (int a=0; a<nbAnt; a++)
memset(samplesVoid[a],0,sampleToByte(nsamps,1)); memset(samplesVoid[a],0,sampleToByte(nsamps,1));
cf_t temp_array[nbAnt][nsamps];
bool apply_noise_per_channel = get_noise_power_dBFS() == INVALID_DBFS_VALUE;
int num_chanmod_channels = 0;
// Add all input nodes signal in the output buffer // Add all input nodes signal in the output buffer
for (int sock = 0; sock < MAX_FD_RFSIMU; sock++) { for (int sock = 0; sock < MAX_FD_RFSIMU; sock++) {
buffer_t *ptr=&t->buf[sock]; buffer_t *ptr=&t->buf[sock];
...@@ -1024,12 +1026,18 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest ...@@ -1024,12 +1026,18 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest
for (int a=0; a<nbAnt; a++) {//loop over number of Rx antennas for (int a=0; a<nbAnt; a++) {//loop over number of Rx antennas
if ( ptr->channel_model != NULL ) { // apply a channel model if ( ptr->channel_model != NULL ) { // apply a channel model
rxAddInput(ptr->circularBuf, (c16_t *) samplesVoid[a], if (num_chanmod_channels == 0) {
memset(temp_array, 0, sizeof(temp_array));
}
num_chanmod_channels++;
rxAddInput(ptr->circularBuf,
temp_array[a],
a, a,
ptr->channel_model, ptr->channel_model,
nsamps, nsamps,
t->nextRxTstamp, t->nextRxTstamp,
CirSize); CirSize,
apply_noise_per_channel);
} }
else { // no channel modeling else { // no channel modeling
int nbAnt_tx = ptr->th.nbAnt; // number of Tx antennas int nbAnt_tx = ptr->th.nbAnt; // number of Tx antennas
...@@ -1063,6 +1071,26 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest ...@@ -1063,6 +1071,26 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest
} // end for a (number of rx antennas) } // end for a (number of rx antennas)
} }
} }
if (apply_noise_per_channel && num_chanmod_channels > 0) {
// Noise is already applied through the channel model
for (int a = 0; a < nbAnt; a++) {
sample_t *out = (sample_t *)samplesVoid[a];
for (int i = 0; i < nsamps; i++) {
out[i].r += lroundf(temp_array[a][i].r);
out[i].i += lroundf(temp_array[a][i].i);
}
}
} else if (num_chanmod_channels > 0) {
// Apply noise from global setting
int16_t noise_power = (int16_t)(32767.0 / powf(10.0, .05 * -get_noise_power_dBFS()));
for (int a = 0; a < nbAnt; a++) {
sample_t *out = (sample_t *)samplesVoid[a];
for (int i = 0; i < nsamps; i++) {
out[i].r += lroundf(temp_array[a][i].r + noise_power * gaussZiggurat(0.0, 1.0));
out[i].i += lroundf(temp_array[a][i].i + noise_power * gaussZiggurat(0.0, 1.0));
}
}
}
*ptimestamp = t->nextRxTstamp; // return the time of the first sample *ptimestamp = t->nextRxTstamp; // return the time of the first sample
t->nextRxTstamp+=nsamps; t->nextRxTstamp+=nsamps;
......
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