Compare commits

...

1 Commits

Author SHA1 Message Date
Bartosz Podrygajlo
ff4c19596d WIP: Proposal for power control for rfsimulator
This implements rx_gain, tx_gain and tx_power for rfsim. A constant sample reference amplitude value
at 0 dBm is selected to be 256. When calculating power, power == 10log10(rms^2) - 10log10(rfsim_k_constant)
rfsim_k_constant = rms^2 at 0dBm == 256*256*2.

This is not integrated with any softmodem so far but some tests are added to show how power could be calculated with rfsim.
2024-07-30 10:37:31 +02:00
7 changed files with 171 additions and 8 deletions

View File

@@ -628,6 +628,7 @@ typedef struct {
uint64_t timestamp; // Timestamp value of first sample
uint32_t option_value; // Option value
uint32_t option_flag; // Option flag
int16_t tx_power;
} samplesBlockHeader_t;
#ifdef __cplusplus

View File

@@ -8,3 +8,13 @@ set_target_properties(rfsimulator PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BI
add_executable(replay_node stored_node.c)
target_link_libraries (replay_node minimal_lib)
if (ENABLE_TESTS)
add_library(rfsimulator_static STATIC
simulator.c
apply_channelmod.c
../../openair1/PHY/TOOLS/signal_energy.c)
target_include_directories(rfsimulator_static PUBLIC .)
target_link_libraries(rfsimulator_static PUBLIC SIMU)
add_subdirectory(tests)
endif()

View File

@@ -58,16 +58,22 @@ void rxAddInput( const c16_t *input_sig,
channel_desc_t *channelDesc,
int nbSamples,
uint64_t TS,
uint32_t CirSize
uint32_t CirSize,
int16_t rx_gain,
int16_t tx_power
) {
// channelDesc->path_loss_dB should contain the total path gain
// so, in actual RF: tx gain + path loss + rx gain (+antenna gain, ...)
// UE and NB gain control to be added
// Fixme: not sure when it is "volts" so dB is 20*log10(...) or "power", so dB is 10*log10(...)
const double pathLossLinear = pow(10,channelDesc->path_loss_dB/20.0);
const double pathLossLinear = pow(10,(channelDesc->path_loss_dB + tx_power)/20.0);
// Energy in one sample to calibrate input noise
// 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;
// Treat noise_power_dB as noise_power_dBm. Convert to sample value. 256 sample value is 0dBm.
const double noise_per_sample = pow(10,channelDesc->noise_power_dB/20.0) * 256;
const double rx_gain_linear = pow(10,rx_gain/20.0);
const uint64_t dd = channelDesc->channel_offset;
const int nbTx=channelDesc->nb_tx;
@@ -95,8 +101,8 @@ void rxAddInput( const c16_t *input_sig,
}
// Fixme: lround(), rount(), ... is detected by valgrind as error, not found why
out_ptr->r += lround(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->r += lround(rx_gain_linear*(rx_tmp.r*pathLossLinear + noise_per_sample*gaussZiggurat(0.0,1.0)));
out_ptr->i += lround(rx_gain_linear*(rx_tmp.i*pathLossLinear + noise_per_sample*gaussZiggurat(0.0,1.0)));
out_ptr++;
}

View File

@@ -23,13 +23,17 @@
#ifndef __RFSIMULATOR_H
#define __RFSIMULATOR_H
#include "openair1/PHY/TOOLS/tools_defs.h"
#include "openair1/SIMULATION/TOOLS/sim.h"
void rxAddInput( const c16_t *input_sig,
c16_t *after_channel_sig,
int rxAnt,
channel_desc_t *channelDesc,
int nbSamples,
uint64_t TS,
uint32_t CirSize
uint32_t CirSize,
int16_t rx_gain,
int16_t tx_power
);
#endif

View File

@@ -177,6 +177,9 @@ typedef struct {
poll_telnetcmdq_func_t poll_telnetcmdq;
int wait_timeout;
double prop_delay_ms;
int tx_power;
int tx_gain;
int rx_gain;
} rfsimulator_state_t;
static int allocCirBuf(rfsimulator_state_t *bridge, int sock)
@@ -612,7 +615,7 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp
buffer_t *b=&t->buf[i];
if (b->conn_sock >= 0 ) {
samplesBlockHeader_t header = {nsamps, nbAnt, timestamp};
samplesBlockHeader_t header = {nsamps, nbAnt, timestamp, 0, 0, t->tx_power + t->tx_gain};
fullwrite(b->conn_sock,&header, sizeof(header), t);
sample_t tmpSamples[nsamps][nbAnt];
@@ -898,7 +901,9 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest
ptr->channel_model,
nsamps,
t->nextRxTstamp,
CirSize);
CirSize,
t->rx_gain,
ptr->th.tx_power);
}
else { // no channel modeling
int nbAnt_tx = ptr->th.nbAnt; // number of Tx antennas

View File

@@ -0,0 +1,5 @@
add_executable(test_rfsimulator test_rfsimulator.cpp)
target_link_libraries(test_rfsimulator PRIVATE rfsimulator_static GTest::gtest minimal_lib nr_common)
add_dependencies(tests test_rfsimulator)
add_test(NAME test_rfsimulator
COMMAND ./test_rfsimulator)

View File

@@ -0,0 +1,132 @@
#include <gtest/gtest.h>
extern "C" {
#include "rfsimulator.h"
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
if (assert) {
abort();
}
exit(EXIT_SUCCESS);
}
configmodule_interface_t *uniqCfg;
void *get_shlibmodule_fptr(char *modname, char *fname)
{
return nullptr;
}
#include "openair1/SIMULATION/TOOLS/sim.h"
#include "nr_common.h"
extern int32_t signal_energy_nodc(int32_t *input,uint32_t length);
}
#include <algorithm>
#include <cmath>
channel_desc_t *get_awgn_channel_106_rb(void)
{
double sample_rate;
unsigned int samples_per_frame;
double tx_bw;
double rx_bw;
double DS_TDL = .03;
get_samplerate_and_bw(1, 106, 0, &sample_rate, &samples_per_frame, &tx_bw, &rx_bw);
auto channel = new_channel_desc_scm(1, 1, AWGN, sample_rate / 1e6, 0, tx_bw, DS_TDL, 0.0, CORR_LEVEL_LOW, 0, 0, 0, -40);
random_channel(channel, 0);
return channel;
}
const int32_t rfsim_0dbm_sample_ref = 256;
const int32_t rfsim_k_value = rfsim_0dbm_sample_ref * rfsim_0dbm_sample_ref * 2;
TEST(rfsimulator, add_rx_input)
{
int size = 12 * 50;
std::vector<c16_t> input;
input.resize(size);
std::fill(input.begin(), input.end(), (c16_t){rfsim_0dbm_sample_ref, rfsim_0dbm_sample_ref});
std::vector<c16_t> output;
output.resize(size);
std::fill(output.begin(), output.end(), (c16_t){0, 0});
int rxAnt = 0;
channel_desc_t *channel = get_awgn_channel_106_rb();
int nbSamples = input.size();
uint64_t TS = 0;
uint32_t CirSize = sizeof(input);
int16_t rx_gain = 0;
int16_t tx_power = 0;
rxAddInput(input.data(), output.data(), rxAnt, channel, nbSamples, TS, CirSize, rx_gain, tx_power);
int32_t input_power = signal_energy_nodc((int32_t*)input.data(), input.size());
int32_t output_power = signal_energy_nodc((int32_t*)output.data(), output.size());
std::cout << "Input : " << 10*log10(input_power) - 10*log10(rfsim_k_value) << " [dBm] " << std::endl;
std::cout << "Output : " << 10*log10(output_power) - 10*log10(rfsim_k_value) << " [dBm]" << std::endl;
channel->path_loss_dB = -3;
random_channel(channel, 0);
std::fill(output.begin(), output.end(), (c16_t){0, 0});
rxAddInput(input.data(), output.data(), rxAnt, channel, nbSamples, TS, CirSize, rx_gain, tx_power);
int32_t attenuated_power = signal_energy_nodc((int32_t*)output.data(), output.size());
std::cout << "Output (3dB loss): " << 10*log10(attenuated_power) - 10*log10(rfsim_k_value) << " [dBm]" << std::endl;
channel->path_loss_dB = 3;
random_channel(channel, 0);
std::fill(output.begin(), output.end(), (c16_t){0, 0});
rxAddInput(input.data(), output.data(), rxAnt, channel, nbSamples, TS, CirSize, rx_gain, tx_power);
int32_t increased_power = signal_energy_nodc((int32_t*)output.data(), output.size());
std::cout << "Output (3dB gain): " << 10*log10(increased_power) - 10*log10(rfsim_k_value) << " [dBm]" << std::endl;
channel->path_loss_dB = 3;
std::fill(output.begin(), output.end(), (c16_t){0, 0});
rxAddInput(input.data(), output.data(), rxAnt, channel, nbSamples, TS, CirSize, rx_gain, tx_power);
increased_power = signal_energy_nodc((int32_t*)output.data(), output.size());
std::cout << "Output (3dB gain) [no channel regeneration]: " << 10*log10(increased_power) - 10*log10(rfsim_k_value) << " [dBm]" << std::endl;
channel->path_loss_dB = 0;
std::fill(output.begin(), output.end(), (c16_t){0, 0});
rxAddInput(input.data(), output.data(), rxAnt, channel, nbSamples, TS, CirSize, rx_gain, 3);
increased_power = signal_energy_nodc((int32_t*)output.data(), output.size());
std::cout << "Output (3dB gain) [increased tx power]: " << 10*log10(increased_power) - 10*log10(rfsim_k_value) << " [dBm]" << std::endl;
channel->path_loss_dB = 0;
std::fill(output.begin(), output.end(), (c16_t){0, 0});
rxAddInput(input.data(), output.data(), rxAnt, channel, nbSamples, TS, CirSize, 3, tx_power);
increased_power = signal_energy_nodc((int32_t*)output.data(), output.size());
std::cout << "Output (3dB gain) [increased rx gain]: " << 10*log10(increased_power) - 10*log10(rfsim_k_value) << " [dBm]" << std::endl;
channel->path_loss_dB = 0;
channel->noise_power_dB = -20;
std::fill(output.begin(), output.end(), (c16_t){0, 0});
std::fill(input.begin(), input.end(), (c16_t){0, 0});
rxAddInput(input.data(), output.data(), rxAnt, channel, nbSamples, TS, CirSize, rx_gain, tx_power);
increased_power = signal_energy_nodc((int32_t*)output.data(), output.size());
std::cout << "Output (0dB gain, " << channel->noise_power_dB << "dBm noise): " << 10*log10(increased_power) - 10*log10(rfsim_k_value) << " [dBm]" << std::endl;
std::fill(input.begin(), input.end(), (c16_t){0, 0});
std::fill(output.begin(), output.end(), (c16_t){0, 0});
rxAddInput(input.data(), output.data(), rxAnt, channel, nbSamples, TS, CirSize, 3, tx_power);
increased_power = signal_energy_nodc((int32_t*)output.data(), output.size());
std::cout << "Output (3dB gain, " << channel->noise_power_dB << "dBm noise): " << 10*log10(increased_power) - 10*log10(rfsim_k_value) << " [dBm]" << std::endl;
channel->path_loss_dB = 0;
channel->noise_power_dB = -30;
random_channel(channel, 0);
auto linear_gain = std::pow(10,3/20.0);
int16_t sample = rfsim_0dbm_sample_ref * linear_gain;
std::fill(input.begin(), input.end(), (c16_t){sample, sample});
std::fill(output.begin(), output.end(), (c16_t){0, 0});
rxAddInput(input.data(), output.data(), rxAnt, channel, nbSamples, TS, CirSize, rx_gain, tx_power);
increased_power = signal_energy_nodc((int32_t*)output.data(), output.size());
std::cout << "Output (3dB) [digital sample gain]: " << 10*log10(increased_power) - 10*log10(rfsim_k_value) << " [dBm]" << std::endl;
}
int main(int argc, char **argv)
{
logInit();
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}