Merge remote-tracking branch 'origin/rfsimu_config' into develop_integration_2019_w36
This commit is contained in:
@@ -410,7 +410,6 @@ typedef int(*oai_transport_initfunc_t)(openair0_device *device, openair0_config_
|
||||
|
||||
#define OPTION_LZ4 0x00000001 // LZ4 compression (option_value is set to compressed size)
|
||||
|
||||
#define sample_t struct complex16 // 2*16 bits complex number
|
||||
|
||||
typedef struct {
|
||||
uint64_t magic; // Magic value (see defines above)
|
||||
|
||||
@@ -1,36 +1,57 @@
|
||||
#General
|
||||
# General
|
||||
This is a RF simulator that allows to test OAI without a RF board.
|
||||
It replaces a actual RF board driver.
|
||||
|
||||
As much as possible, it works like a RF board, but not in realtime: it can run faster than realtime if there is enough CPU or slower (it is CPU bound instead of real time RF sampling bound)
|
||||
|
||||
#build
|
||||
# build
|
||||
|
||||
## From build_oai
|
||||
You can build it the same way, and together with actual RF driver
|
||||
## From [build_oai](../../../doc/BUILD.md) script
|
||||
The RF simulator is implemented as an oai device and is always build when you build the oai eNB or the oai UE.
|
||||
Using the `-w SIMU` option it is possible to just re-build the RF simulator device
|
||||
|
||||
Example:
|
||||
```bash
|
||||
./build_oai --ue-nas-use-tun --UE --eNB -w SIMU
|
||||
./build_oai --UE --eNB
|
||||
Will compile UE
|
||||
Will compile eNB
|
||||
CMAKE_CMD=cmake ..
|
||||
No local radio head and no transport protocol selected
|
||||
No radio head has been selected (HW set to None)
|
||||
No transport protocol has been selected (TP set to None)
|
||||
RF HW set to None
|
||||
Flags for Deadline scheduler: False
|
||||
..................
|
||||
.................
|
||||
Compiling rfsimulator
|
||||
Log file for compilation has been written to: /usr/local/oai/rfsimu_config/openairinterface5g/cmake_targets/log/rfsimulator.Rel14.txt
|
||||
rfsimulator compiled
|
||||
......................
|
||||
......................
|
||||
```
|
||||
It is also possible to build actual RF and use choose on each run:
|
||||
```bash
|
||||
./build_oai --ue-nas-use-tun --UE --eNB -w USRP --rfsimulator
|
||||
```
|
||||
Will build both the eNB (lte-softmodem) and the UE (lte-uesoftmodem)
|
||||
We recommend to use the option --ue-nas-use-tun that is much simpler to use than the OAI kernel driver.
|
||||
|
||||
## Add the rfsimulator after initial build
|
||||
After any regular build, you can compile the driver
|
||||
After any regular build, you can compile the device, from the build directory
|
||||
```bash
|
||||
cd <the_compilation_dir_from_bouild_oai_script>/build
|
||||
cd <path to oai sources>/openairinterface5g/cmake_targets/lte_build_oai/build
|
||||
make rfsimulator
|
||||
```
|
||||
Then, you can use it freely
|
||||
this is equivalent to using `-w SIMU` when running the `build_oai` script.
|
||||
e
|
||||
|
||||
# Usage
|
||||
Setting the env variable RFSIMULATOR enables the RF board simulator
|
||||
It should the set to "server" in the eNB or gNB
|
||||
To use the RF simulator you add the `--rfsim` option to the command line. By default the RF simulator device will try to connect to host 127.0.0.1, port 4043, which is usually the behavior for the UE.
|
||||
The RF simulator is using the configuration module, its parameters are defined in a specific section called "rfsimulator"
|
||||
|
||||
| parameter | usage | default |
|
||||
|:---------------------|:------------------------------------------------------------------------------------------------------------------|----:|
|
||||
| serveraddr | ip address to connect to, or "enb" to behave as a tcp server | 127.0.0.1 |
|
||||
| serverport | port number to connect to or to listen on (eNB, which behaved as a tcp server) | 4043 |
|
||||
| options | list of comma separated run-time options, two are supported: `chanmod` to enable channel modeling and `saviq` to write transmitted iqs to a file | all options disabled |
|
||||
| modelname | Name of the channel model to apply on received iqs when the `chanmod` option is enabled | AWGN |
|
||||
| IQfile | Path to the file to be used to store iqs, when the `saviq`option is enabled | /tmp/rfsimulator.iqs |
|
||||
|
||||
Setting the env variable RFSIMULATOR can be used instead of using the serveraddr parameter, it is to preserve compatibility with previous version.
|
||||
|
||||
## 4G case
|
||||
For the UE, it should be set to the IP address of the eNB
|
||||
@@ -38,13 +59,14 @@ example:
|
||||
```bash
|
||||
sudo RFSIMULATOR=192.168.2.200 ./lte-uesoftmodem -C 2685000000 -r 50
|
||||
```
|
||||
Except this, the UE and the eNB can be used as it the RF is real
|
||||
Except this, the UE and the eNB can be used as it the RF is real. noS1 mode can also be used with the RF simulator.
|
||||
|
||||
If you reach 'RA not active' on UE, be careful to generate a valid SIM
|
||||
If you reach 'RA not active' on UE, be careful to generate a valid SIM.
|
||||
```bash
|
||||
$OPENAIR_DIR/targets/bin/conf2uedata -c $OPENAIR_DIR/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf -o .
|
||||
```
|
||||
## 5G case
|
||||
5G RF simulator will be aligned with 4G as the effort to merge 5G specifuc branches into develop is making progress.
|
||||
After regular build, add the simulation driver
|
||||
(don't use ./build_oai -w SIMU until we merge 4G and 5G branches)
|
||||
```bash
|
||||
@@ -66,7 +88,7 @@ In UE, you can add "-d" to get the softscope
|
||||
|
||||
You can store emitted I/Q samples:
|
||||
|
||||
If you set the environment variable: saveIQfile to a file name
|
||||
If you set the option `saviq`
|
||||
The simulator will write all IQ samples into this file
|
||||
|
||||
Then, you can replay with the executable "replay_node"
|
||||
@@ -83,11 +105,11 @@ If you have existing stored I/Q, you can adpat the tool "replay_node" to convert
|
||||
The format intend to be compatible with the OAI store/replay feature on USRP
|
||||
|
||||
### Channel simulation
|
||||
The RF channel simulator is called.
|
||||
In current version all channel paramters are hard coded in the call to:
|
||||
When the `chanmod` option is enabled, The RF channel simulator is called.
|
||||
In current version all channel paramters are set depending on the model name via a call to:
|
||||
```
|
||||
new_channel_desc_scm(bridge->tx_num_channels,bridge->rx_num_channels,
|
||||
AWGN,
|
||||
<model name>,
|
||||
bridge->sample_rate,
|
||||
bridge->tx_bw,
|
||||
0.0, // forgetting_factor
|
||||
@@ -95,7 +117,7 @@ new_channel_desc_scm(bridge->tx_num_channels,bridge->rx_num_channels,
|
||||
0); // path_loss in dB
|
||||
```
|
||||
Only the input noise can be changed on command line with -s parameter.
|
||||
With path loss = 0 set "-s 5" to see a little noise
|
||||
With path loss = 0 set "-s 5" to see a little noise. -s is a shortcut to `channelmod.s`. It is expected to enhance the channel modedelization flexibility via the addition of more parameters in the channelmod section.
|
||||
|
||||
#Caveacts
|
||||
# Caveacts
|
||||
Still issues in power control: txgain, rxgain are not used
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
Author: Laurent THOMAS, Open Cells for Nokia
|
||||
copyleft: OpenAirInterface Software Alliance and it's licence
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#include <common/utils/assertions.h>
|
||||
#include <common/utils/LOG/log.h>
|
||||
#include <common/config/config_userapi.h>
|
||||
#include <openair1/SIMULATION/TOOLS/sim.h>
|
||||
|
||||
/*
|
||||
Legacy study:
|
||||
The parameters are:
|
||||
gain&loss (decay, signal power, ...)
|
||||
either a fixed gain in dB, a target power in dBm or ACG (automatic control gain) to a target average
|
||||
=> don't redo the AGC, as it was used in UE case, that must have a AGC inside the UE
|
||||
will be better to handle the "set_gain()" called by UE to apply it's gain (enable test of UE power loop)
|
||||
lin_amp = pow(10.0,.05*txpwr_dBm)/sqrt(nb_tx_antennas);
|
||||
a lot of operations in legacy, grouped in one simulation signal decay: txgain*decay*rxgain
|
||||
|
||||
multi_path (auto convolution, ISI, ...)
|
||||
either we regenerate the channel (call again random_channel(desc,0)), or we keep it over subframes
|
||||
legacy: we regenerate each sub frame in UL, and each frame only in DL
|
||||
*/
|
||||
void rxAddInput( struct complex16 *input_sig, struct complex16 *after_channel_sig,
|
||||
int rxAnt,
|
||||
channel_desc_t *channelDesc,
|
||||
int nbSamples,
|
||||
uint64_t TS,
|
||||
uint32_t CirSize
|
||||
) {
|
||||
// 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);
|
||||
// Energy in one sample to calibrate input noise
|
||||
//Fixme: modified the N0W computation, not understand the origin value
|
||||
const double KT=1.38e-23*290; //Boltzman*temperature
|
||||
// sampling rate is linked to acquisition band (the input pass band filter)
|
||||
const double noise_figure_watt = KT*channelDesc->sampling_rate;
|
||||
// Fixme: how to convert a noise in Watt into a 12 bits value out of the RF ADC ?
|
||||
// the parameter "-s" is declared as SNR, but the input power is not well defined
|
||||
// −132.24 dBm is a LTE subcarrier noise, that was used in origin code (15KHz BW thermal noise)
|
||||
const double rxGain= 132.24 - channelmod_get_snr_dB();
|
||||
// sqrt(4*noise_figure_watt) is the thermal noise factor (volts)
|
||||
// fixme: the last constant is pure trial results to make decent noise
|
||||
const double noise_per_sample = sqrt(4*noise_figure_watt) * pow(10,rxGain/20) *10;
|
||||
// Fixme: we don't fill the offset length samples at begining ?
|
||||
// anyway, in today code, channel_offset=0
|
||||
const int dd = abs(channelDesc->channel_offset);
|
||||
const int nbTx=channelDesc->nb_tx;
|
||||
|
||||
for (int i=0; i<((int)nbSamples-dd); i++) {
|
||||
struct complex16 *out_ptr=after_channel_sig+dd+i;
|
||||
struct complex rx_tmp= {0};
|
||||
|
||||
for (int txAnt=0; txAnt < nbTx; txAnt++) {
|
||||
const struct complex *channelModel= channelDesc->ch[rxAnt+(txAnt*channelDesc->nb_rx)];
|
||||
|
||||
//const struct complex *channelModelEnd=channelModel+channelDesc->channel_length;
|
||||
for (int l = 0; l<(int)channelDesc->channel_length; l++) {
|
||||
// let's assume TS+i >= l
|
||||
// fixme: the rfsimulator current structure is interleaved antennas
|
||||
// this has been designed to not have to wait a full block transmission
|
||||
// but it is not very usefull
|
||||
// it would be better to split out each antenna in a separate flow
|
||||
// that will allow to mix ru antennas freely
|
||||
struct complex16 tx16=input_sig[((TS+i-l)*nbTx+txAnt)%CirSize];
|
||||
rx_tmp.x += tx16.r * channelModel[l].x - tx16.i * channelModel[l].y;
|
||||
rx_tmp.y += tx16.i * channelModel[l].x + tx16.r * channelModel[l].y;
|
||||
} //l
|
||||
}
|
||||
|
||||
out_ptr->r += round(rx_tmp.x*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0));
|
||||
out_ptr->i += round(rx_tmp.y*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0));
|
||||
out_ptr++;
|
||||
}
|
||||
|
||||
if ( (TS*nbTx)%CirSize+nbSamples <= CirSize )
|
||||
// Cast to a wrong type for compatibility !
|
||||
LOG_D(HW,"Input power %f, output power: %f, channel path loss %f, noise coeff: %f \n",
|
||||
10*log10((double)signal_energy((int32_t *)&input_sig[(TS*nbTx)%CirSize], nbSamples)),
|
||||
10*log10((double)signal_energy((int32_t *)after_channel_sig, nbSamples)),
|
||||
channelDesc->path_loss_dB,
|
||||
10*log10(noise_per_sample));
|
||||
}
|
||||
@@ -24,12 +24,15 @@
|
||||
|
||||
#include <common/utils/assertions.h>
|
||||
#include <common/utils/LOG/log.h>
|
||||
#include <common/utils/load_module_shlib.h>
|
||||
#include <common/config/config_userapi.h>
|
||||
#include "common_lib.h"
|
||||
#include <openair1/PHY/defs_eNB.h>
|
||||
#include "openair1/PHY/defs_UE.h"
|
||||
#define CHANNELMOD_DYNAMICLOAD
|
||||
#include <openair1/SIMULATION/TOOLS/sim.h>
|
||||
|
||||
#define PORT 4043 //TCP port for this simulator
|
||||
#define PORT 4043 //default TCP port for this simulator
|
||||
#define CirSize 3072000 // 100ms is enough
|
||||
#define sampleToByte(a,b) ((a)*(b)*sizeof(sample_t))
|
||||
#define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b)))
|
||||
@@ -39,12 +42,31 @@
|
||||
|
||||
// Fixme: datamodel, external variables in .h files, ...
|
||||
#include <common/ran_context.h>
|
||||
extern double snr_dB;
|
||||
|
||||
extern RAN_CONTEXT_t RC;
|
||||
//
|
||||
|
||||
#define RFSIMU_SECTION "rfsimulator"
|
||||
#define RFSIMU_OPTIONS_PARAMNAME "options"
|
||||
# define RFSIM_CONFIG_HELP_OPTIONS " list of comma separated options to enable rf simulator functionalities. Available options: \n"\
|
||||
" chanmod: enable channel modelisation\n"\
|
||||
" saviq: enable saving written iqs to a file\n"
|
||||
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* configuration parameters for the rfsimulator device */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define RFSIMULATOR_PARAMS_DESC {\
|
||||
{"serveraddr", "<ip address to connect to>\n", 0, strptr:&(rfsimulator->ip), defstrval:"127.0.0.1", TYPE_STRING, 0 },\
|
||||
{"serverport", "<port to connect to>\n", 0, u16ptr:&(rfsimulator->port), defuintval:PORT, TYPE_UINT16, 0 },\
|
||||
{RFSIMU_OPTIONS_PARAMNAME, RFSIM_CONFIG_HELP_OPTIONS, 0, strlistptr:NULL, defstrlistval:NULL, TYPE_STRINGLIST,0},\
|
||||
{"IQfile", "<file path to use when saving IQs>\n", 0, strptr:&(saveF), defstrval:"/tmp/rfsimulator.iqs",TYPE_STRING, 0 },\
|
||||
{"modelname", "<channel model name>\n", 0, strptr:&(modelname), defstrval:"AWGN", TYPE_STRING, 0 }\
|
||||
};
|
||||
|
||||
pthread_mutex_t Sockmutex;
|
||||
|
||||
typedef struct complex16 sample_t; // 2*16 bits complex number
|
||||
|
||||
typedef struct buffer_s {
|
||||
int conn_sock;
|
||||
openair0_timestamp lastReceivedTS;
|
||||
@@ -63,90 +85,16 @@ typedef struct {
|
||||
openair0_timestamp nextTimestamp;
|
||||
uint64_t typeStamp;
|
||||
char *ip;
|
||||
uint16_t port;
|
||||
int saveIQfile;
|
||||
buffer_t buf[FD_SETSIZE];
|
||||
int rx_num_channels;
|
||||
int tx_num_channels;
|
||||
double sample_rate;
|
||||
double tx_bw;
|
||||
int channelmod;
|
||||
} rfsimulator_state_t;
|
||||
|
||||
/*
|
||||
Legacy study:
|
||||
The parameters are:
|
||||
gain&loss (decay, signal power, ...)
|
||||
either a fixed gain in dB, a target power in dBm or ACG (automatic control gain) to a target average
|
||||
=> don't redo the AGC, as it was used in UE case, that must have a AGC inside the UE
|
||||
will be better to handle the "set_gain()" called by UE to apply it's gain (enable test of UE power loop)
|
||||
lin_amp = pow(10.0,.05*txpwr_dBm)/sqrt(nb_tx_antennas);
|
||||
a lot of operations in legacy, grouped in one simulation signal decay: txgain*decay*rxgain
|
||||
|
||||
multi_path (auto convolution, ISI, ...)
|
||||
either we regenerate the channel (call again random_channel(desc,0)), or we keep it over subframes
|
||||
legacy: we regenerate each sub frame in UL, and each frame only in DL
|
||||
*/
|
||||
void rxAddInput( struct complex16 *input_sig, struct complex16 *after_channel_sig,
|
||||
int rxAnt,
|
||||
channel_desc_t *channelDesc,
|
||||
int nbSamples,
|
||||
uint64_t TS
|
||||
) {
|
||||
// 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);
|
||||
// Energy in one sample to calibrate input noise
|
||||
//Fixme: modified the N0W computation, not understand the origin value
|
||||
const double KT=1.38e-23*290; //Boltzman*temperature
|
||||
// sampling rate is linked to acquisition band (the input pass band filter)
|
||||
const double noise_figure_watt = KT*channelDesc->sampling_rate;
|
||||
// Fixme: how to convert a noise in Watt into a 12 bits value out of the RF ADC ?
|
||||
// the parameter "-s" is declared as SNR, but the input power is not well defined
|
||||
// −132.24 dBm is a LTE subcarrier noise, that was used in origin code (15KHz BW thermal noise)
|
||||
const double rxGain= 132.24 - snr_dB;
|
||||
// sqrt(4*noise_figure_watt) is the thermal noise factor (volts)
|
||||
// fixme: the last constant is pure trial results to make decent noise
|
||||
const double noise_per_sample = sqrt(4*noise_figure_watt) * pow(10,rxGain/20) *10;
|
||||
// Fixme: we don't fill the offset length samples at begining ?
|
||||
// anyway, in today code, channel_offset=0
|
||||
const int dd = abs(channelDesc->channel_offset);
|
||||
const int nbTx=channelDesc->nb_tx;
|
||||
|
||||
for (int i=0; i<((int)nbSamples-dd); i++) {
|
||||
struct complex16 *out_ptr=after_channel_sig+dd+i;
|
||||
struct complex rx_tmp= {0};
|
||||
|
||||
for (int txAnt=0; txAnt < nbTx; txAnt++) {
|
||||
const struct complex *channelModel= channelDesc->ch[rxAnt+(txAnt*channelDesc->nb_rx)];
|
||||
|
||||
//const struct complex *channelModelEnd=channelModel+channelDesc->channel_length;
|
||||
for (int l = 0; l<(int)channelDesc->channel_length; l++) {
|
||||
// let's assume TS+i >= l
|
||||
// fixme: the rfsimulator current structure is interleaved antennas
|
||||
// this has been designed to not have to wait a full block transmission
|
||||
// but it is not very usefull
|
||||
// it would be better to split out each antenna in a separate flow
|
||||
// that will allow to mix ru antennas freely
|
||||
struct complex16 tx16=input_sig[((TS+i-l)*nbTx+txAnt)%CirSize];
|
||||
rx_tmp.x += tx16.r * channelModel[l].x - tx16.i * channelModel[l].y;
|
||||
rx_tmp.y += tx16.i * channelModel[l].x + tx16.r * channelModel[l].y;
|
||||
} //l
|
||||
}
|
||||
|
||||
out_ptr->r += round(rx_tmp.x*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0));
|
||||
out_ptr->i += round(rx_tmp.y*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0));
|
||||
out_ptr++;
|
||||
}
|
||||
|
||||
if ( (TS*nbTx)%CirSize+nbSamples <= CirSize )
|
||||
// Cast to a wrong type for compatibility !
|
||||
LOG_D(HW,"Input power %f, output power: %f, channel path loss %f, noise coeff: %f \n",
|
||||
10*log10((double)signal_energy((int32_t *)&input_sig[(TS*nbTx)%CirSize], nbSamples)),
|
||||
10*log10((double)signal_energy((int32_t *)after_channel_sig, nbSamples)),
|
||||
channelDesc->path_loss_dB,
|
||||
10*log10(noise_per_sample));
|
||||
}
|
||||
|
||||
void allocCirBuf(rfsimulator_state_t *bridge, int sock) {
|
||||
buffer_t *ptr=&bridge->buf[sock];
|
||||
@@ -164,26 +112,29 @@ void allocCirBuf(rfsimulator_state_t *bridge, int sock) {
|
||||
ev.events = EPOLLIN | EPOLLRDHUP;
|
||||
ev.data.fd = sock;
|
||||
AssertFatal(epoll_ctl(bridge->epollfd, EPOLL_CTL_ADD, sock, &ev) != -1, "");
|
||||
// create channel simulation model for this mode reception
|
||||
// snr_dB is pure global, coming from configuration paramter "-s"
|
||||
// Fixme: referenceSignalPower should come from the right place
|
||||
// but the datamodel is inconsistant
|
||||
// legacy: RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower
|
||||
// (must not come from ru[]->frame_parms as it doesn't belong to ru !!!)
|
||||
// Legacy sets it as:
|
||||
// ptr->channel_model->path_loss_dB = -132.24 + snr_dB - RC.ru[0]->frame_parms->pdsch_config_common.referenceSignalPower;
|
||||
// we use directly the paramter passed on the command line ("-s")
|
||||
// the value channel_model->path_loss_dB seems only a storage place (new_channel_desc_scm() only copy the passed value)
|
||||
// Legacy changes directlty the variable channel_model->path_loss_dB place to place
|
||||
// while calling new_channel_desc_scm() with path losses = 0
|
||||
ptr->channel_model=new_channel_desc_scm(bridge->tx_num_channels,bridge->rx_num_channels,
|
||||
AWGN,
|
||||
bridge->sample_rate,
|
||||
bridge->tx_bw,
|
||||
0.0, // forgetting_factor
|
||||
0, // maybe used for TA
|
||||
0); // path_loss in dB
|
||||
random_channel(ptr->channel_model,false);
|
||||
|
||||
if ( bridge->channelmod > 0) {
|
||||
// create channel simulation model for this mode reception
|
||||
// snr_dB is pure global, coming from configuration paramter "-s"
|
||||
// Fixme: referenceSignalPower should come from the right place
|
||||
// but the datamodel is inconsistant
|
||||
// legacy: RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower
|
||||
// (must not come from ru[]->frame_parms as it doesn't belong to ru !!!)
|
||||
// Legacy sets it as:
|
||||
// ptr->channel_model->path_loss_dB = -132.24 + snr_dB - RC.ru[0]->frame_parms->pdsch_config_common.referenceSignalPower;
|
||||
// we use directly the paramter passed on the command line ("-s")
|
||||
// the value channel_model->path_loss_dB seems only a storage place (new_channel_desc_scm() only copy the passed value)
|
||||
// Legacy changes directlty the variable channel_model->path_loss_dB place to place
|
||||
// while calling new_channel_desc_scm() with path losses = 0
|
||||
ptr->channel_model=new_channel_desc_scm(bridge->tx_num_channels,bridge->rx_num_channels,
|
||||
bridge->channelmod,
|
||||
bridge->sample_rate,
|
||||
bridge->tx_bw,
|
||||
0.0, // forgetting_factor
|
||||
0, // maybe used for TA
|
||||
0); // path_loss in dB
|
||||
random_channel(ptr->channel_model,false);
|
||||
}
|
||||
}
|
||||
|
||||
void removeCirBuf(rfsimulator_state_t *bridge, int sock) {
|
||||
@@ -212,6 +163,7 @@ void socketError(rfsimulator_state_t *bridge, int sock) {
|
||||
rfsimulator: error: you have to run one UE and one eNB\n\
|
||||
For this, export RFSIMULATOR=enb (eNB case) or \n\
|
||||
RFSIMULATOR=<an ip address> (UE case)\n\
|
||||
or use rfsimulator.serveraddr configuration option\n\
|
||||
\x1b[m"
|
||||
|
||||
enum blocking_t {
|
||||
@@ -266,6 +218,48 @@ void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator) {
|
||||
char *saveF=NULL;
|
||||
char *modelname=NULL;
|
||||
paramdef_t rfsimu_params[] = RFSIMULATOR_PARAMS_DESC;
|
||||
int p = config_paramidx_fromname(rfsimu_params,sizeof(rfsimu_params)/sizeof(paramdef_t), RFSIMU_OPTIONS_PARAMNAME) ;
|
||||
int ret = config_get( rfsimu_params,sizeof(rfsimu_params)/sizeof(paramdef_t),RFSIMU_SECTION);
|
||||
AssertFatal(ret >= 0, "configuration couldn't be performed");
|
||||
rfsimulator->saveIQfile = -1;
|
||||
|
||||
for(int i=0; i<rfsimu_params[p].numelt ; i++) {
|
||||
if (strcmp(rfsimu_params[p].strlistptr[i],"saviq") == 0) {
|
||||
rfsimulator->saveIQfile=open(saveF,O_APPEND| O_CREAT|O_TRUNC | O_WRONLY, 0666);
|
||||
|
||||
if ( rfsimulator->saveIQfile != -1 )
|
||||
LOG_I(HW,"rfsimulator: will save written IQ samples in %s\n", saveF);
|
||||
else
|
||||
LOG_E(HW, "can't open %s for IQ saving (%s)\n", saveF, strerror(errno));
|
||||
|
||||
break;
|
||||
} else if (strcmp(rfsimu_params[p].strlistptr[i],"chanmod") == 0) {
|
||||
init_channelmod();
|
||||
rfsimulator->channelmod=modelid_fromname(modelname);
|
||||
} else {
|
||||
fprintf(stderr,"Unknown rfsimulator option: %s\n",rfsimu_params[p].strlistptr[i]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* for compatibility keep environment variable usage */
|
||||
if ( getenv("RFSIMULATOR") != NULL ) {
|
||||
rfsimulator->ip=getenv("RFSIMULATOR");
|
||||
}
|
||||
|
||||
if ( strncasecmp(rfsimulator->ip,"enb",3) == 0 ||
|
||||
strncasecmp(rfsimulator->ip,"server",3) == 0 )
|
||||
rfsimulator->typeStamp = ENB_MAGICDL_FDD;
|
||||
else
|
||||
rfsimulator->typeStamp = UE_MAGICDL_FDD;
|
||||
}
|
||||
|
||||
int server_start(openair0_device *device) {
|
||||
rfsimulator_state_t *t = (rfsimulator_state_t *) device->priv;
|
||||
t->typeStamp=ENB_MAGICDL_FDD;
|
||||
@@ -276,7 +270,7 @@ int server_start(openair0_device *device) {
|
||||
sin_family:
|
||||
AF_INET,
|
||||
sin_port:
|
||||
htons(PORT),
|
||||
htons(t->port),
|
||||
sin_addr:
|
||||
{ s_addr: INADDR_ANY }
|
||||
};
|
||||
@@ -298,7 +292,7 @@ int start_ue(openair0_device *device) {
|
||||
sin_family:
|
||||
AF_INET,
|
||||
sin_port:
|
||||
htons(PORT),
|
||||
htons(t->port),
|
||||
sin_addr:
|
||||
{ s_addr: INADDR_ANY }
|
||||
};
|
||||
@@ -306,7 +300,7 @@ sin_addr:
|
||||
bool connected=false;
|
||||
|
||||
while(!connected) {
|
||||
LOG_I(HW,"rfsimulator: trying to connect to %s:%d\n", t->ip, PORT);
|
||||
LOG_I(HW,"rfsimulator: trying to connect to %s:%d\n", t->ip, t->port);
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
|
||||
LOG_I(HW,"rfsimulator: connection established\n");
|
||||
@@ -326,13 +320,13 @@ int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, voi
|
||||
rfsimulator_state_t *t = device->priv;
|
||||
LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp);
|
||||
|
||||
|
||||
for (int i=0; i<FD_SETSIZE; i++) {
|
||||
buffer_t *b=&t->buf[i];
|
||||
|
||||
if (b->conn_sock >= 0 ) {
|
||||
if ( abs((double)b->lastWroteTS-timestamp) > (double)CirSize)
|
||||
LOG_E(HW,"Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->lastWroteTS, b->lastReceivedTS);
|
||||
LOG_E(HW,"Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->lastWroteTS, b->lastReceivedTS);
|
||||
|
||||
samplesBlockHeader_t header= {t->typeStamp, nsamps, nbAnt, timestamp};
|
||||
fullwrite(b->conn_sock,&header, sizeof(header), t);
|
||||
sample_t tmpSamples[nsamps][nbAnt];
|
||||
@@ -487,41 +481,50 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo
|
||||
|
||||
if ( first_sock == FD_SETSIZE ) {
|
||||
// no connected device (we are eNB, no UE is connected)
|
||||
if ( t->nextTimestamp == 0)
|
||||
LOG_W(HW,"No connected device, generating void samples...\n");
|
||||
|
||||
if (!flushInput(t, 10)) {
|
||||
for (int x=0; x < nbAnt; x++)
|
||||
memset(samplesVoid[x],0,sampleToByte(nsamps,1));
|
||||
|
||||
t->nextTimestamp+=nsamps;
|
||||
LOG_W(HW,"Generated void samples for Rx: %ld\n", t->nextTimestamp);
|
||||
|
||||
if ( ((t->nextTimestamp/nsamps)%100) == 0)
|
||||
LOG_W(HW,"Generated void samples for Rx: %ld\n", t->nextTimestamp);
|
||||
|
||||
*ptimestamp = t->nextTimestamp-nsamps;
|
||||
pthread_mutex_unlock(&Sockmutex);
|
||||
return nsamps;
|
||||
}
|
||||
} else {
|
||||
|
||||
bool have_to_wait;
|
||||
|
||||
do {
|
||||
have_to_wait=false;
|
||||
|
||||
for ( int sock=0; sock<FD_SETSIZE; sock++) {
|
||||
buffer_t *b=&t->buf[sock];
|
||||
buffer_t *b=&t->buf[sock];
|
||||
|
||||
if ( b->circularBuf) {
|
||||
LOG_D(HW,"sock: %d, lastWroteTS: %lu, lastRecvTS: %lu, TS must be avail: %lu\n",
|
||||
sock, b->lastWroteTS,
|
||||
b->lastReceivedTS,
|
||||
t->nextTimestamp+nsamps);
|
||||
if ( b->lastReceivedTS > b->lastWroteTS ) {
|
||||
// The caller momdem (NB, UE, ...) must send Tx in advance, so we fill TX if Rx is in advance
|
||||
// This occurs for example when UE is in sync mode: it doesn't transmit
|
||||
// with USRP, it seems ok: if "tx stream" is off, we may consider it actually cuts the Tx power
|
||||
struct complex16 v={0};
|
||||
void *samplesVoid[b->th.nbAnt];
|
||||
for ( int i=0; i <b->th.nbAnt; i++)
|
||||
samplesVoid[i]=(void*)&v;
|
||||
rfsimulator_write(device, b->lastReceivedTS, samplesVoid, 1, b->th.nbAnt, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if ( b->lastReceivedTS > b->lastWroteTS ) {
|
||||
// The caller momdem (NB, UE, ...) must send Tx in advance, so we fill TX if Rx is in advance
|
||||
// This occurs for example when UE is in sync mode: it doesn't transmit
|
||||
// with USRP, it seems ok: if "tx stream" is off, we may consider it actually cuts the Tx power
|
||||
struct complex16 v= {0};
|
||||
void *samplesVoid[b->th.nbAnt];
|
||||
|
||||
for ( int i=0; i <b->th.nbAnt; i++)
|
||||
samplesVoid[i]=(void *)&v;
|
||||
|
||||
rfsimulator_write(device, b->lastReceivedTS, samplesVoid, 1, b->th.nbAnt, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if ( b->circularBuf )
|
||||
if ( t->nextTimestamp+nsamps > b->lastReceivedTS ) {
|
||||
@@ -555,13 +558,24 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo
|
||||
if (reGenerateChannel)
|
||||
random_channel(ptr->channel_model,0);
|
||||
|
||||
for (int a=0; a<nbAnt; a++)
|
||||
rxAddInput( ptr->circularBuf, (struct complex16 *) samplesVoid[a],
|
||||
a,
|
||||
ptr->channel_model,
|
||||
nsamps,
|
||||
t->nextTimestamp
|
||||
);
|
||||
for (int a=0; a<nbAnt; a++) {
|
||||
if ( ptr->channel_model != NULL ) // apply a channel model
|
||||
rxAddInput( ptr->circularBuf, (struct complex16 *) samplesVoid[a],
|
||||
a,
|
||||
ptr->channel_model,
|
||||
nsamps,
|
||||
t->nextTimestamp,
|
||||
CirSize
|
||||
);
|
||||
else { // no channel modeling
|
||||
sample_t *out=(sample_t *)samplesVoid[a];
|
||||
|
||||
for ( int i=0; i < nsamps; i++ ) {
|
||||
out[i].r+=ptr->circularBuf[((t->nextTimestamp+i)*nbAnt+a)%CirSize].r;
|
||||
out[i].i+=ptr->circularBuf[((t->nextTimestamp+i)*nbAnt+a)%CirSize].i;
|
||||
}
|
||||
} // end of no channel modeling
|
||||
} // end for a...
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,33 +617,9 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
// to change the log level, use this on command line
|
||||
// --log_config.hw_log_level debug
|
||||
rfsimulator_state_t *rfsimulator = (rfsimulator_state_t *)calloc(sizeof(rfsimulator_state_t),1);
|
||||
|
||||
if ((rfsimulator->ip=getenv("RFSIMULATOR")) == NULL ) {
|
||||
LOG_E(HW,helpTxt);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rfsimulator_readconfig(rfsimulator);
|
||||
pthread_mutex_init(&Sockmutex, NULL);
|
||||
|
||||
if ( strncasecmp(rfsimulator->ip,"enb",3) == 0 ||
|
||||
strncasecmp(rfsimulator->ip,"server",3) == 0 )
|
||||
rfsimulator->typeStamp = ENB_MAGICDL_FDD;
|
||||
else
|
||||
rfsimulator->typeStamp = UE_MAGICDL_FDD;
|
||||
|
||||
LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == ENB_MAGICDL_FDD ? "(eg)NB" : "UE");
|
||||
char *saveF;
|
||||
|
||||
if ((saveF=getenv("saveIQfile")) != NULL) {
|
||||
rfsimulator->saveIQfile=open(saveF,O_APPEND| O_CREAT|O_TRUNC | O_WRONLY, 0666);
|
||||
|
||||
if ( rfsimulator->saveIQfile != -1 )
|
||||
LOG_I(HW,"rfsimulator: will save written IQ samples in %s\n", saveF);
|
||||
else
|
||||
LOG_E(HW, "can't open %s for IQ saving (%s)\n", saveF, strerror(errno));
|
||||
} else
|
||||
rfsimulator->saveIQfile = -1;
|
||||
|
||||
device->trx_start_func = rfsimulator->typeStamp == ENB_MAGICDL_FDD ?
|
||||
server_start :
|
||||
start_ue;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <common/utils/simple_executable.h>
|
||||
|
||||
volatile int oai_exit = 0;
|
||||
|
||||
void fullwrite(int fd, void *_buf, int count) {
|
||||
char *buf = _buf;
|
||||
@@ -123,7 +124,7 @@ int main(int argc, char *argv[]) {
|
||||
setblocking(serviceSock, blocking);
|
||||
AssertFatal(read(fd,&header,sizeof(header)), "");
|
||||
fullwrite(serviceSock, &header, sizeof(header));
|
||||
int dataSize=sizeof(sample_t)*header.size*header.nbAnt;
|
||||
int dataSize=sizeof(int32_t)*header.size*header.nbAnt;
|
||||
|
||||
if (dataSize>bufSize) {
|
||||
void * new_buff = realloc(buff, dataSize);
|
||||
|
||||
@@ -275,12 +275,24 @@ NETWORK_CONTROLLER :
|
||||
THREAD_STRUCT = (
|
||||
{
|
||||
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
|
||||
parallel_config = "PARALLEL_RU_L1_TRX_SPLIT";
|
||||
parallel_config = "PARALLEL_SINGLE_THREAD";
|
||||
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
|
||||
worker_config = "WORKER_ENABLE";
|
||||
}
|
||||
);
|
||||
|
||||
/*
|
||||
#example config for rfsimulator
|
||||
rfsimulator :
|
||||
{
|
||||
serveraddr = "enb";
|
||||
serverport = "4043";
|
||||
options = ("saviq");
|
||||
modelname = "AWGN";
|
||||
IQfile = "/tmp/rfsimulator.iqs";
|
||||
};
|
||||
*/
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level ="info";
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
static softmodem_params_t softmodem_params;
|
||||
char *parallel_config=NULL;
|
||||
char *worker_config=NULL;
|
||||
double snr_dB=25;
|
||||
|
||||
|
||||
uint64_t get_softmodem_optmask(void) {
|
||||
return softmodem_params.optmask;
|
||||
|
||||
@@ -78,7 +78,6 @@
|
||||
#define CONFIG_HLP_MSLOTS "Skip the missed slots/subframes \n"
|
||||
#define CONFIG_HLP_ULMCS "Set the maximum uplink MCS\n"
|
||||
#define CONFIG_HLP_TDD "Set hardware to TDD mode (default: FDD). Used only with -U (otherwise set in config file).\n"
|
||||
#define CONFIG_HLP_SNR "Set average SNR in dB (for --siml1 option)\n"
|
||||
#define CONFIG_HLP_UE "Set the lte softmodem as a UE\n"
|
||||
#define CONFIG_HLP_TQFS "Apply three-quarter of sampling frequency, 23.04 Msps to reduce the data rate on USB/PCIe transfers (only valid for 20 MHz)\n"
|
||||
#define CONFIG_HLP_TPORT "tracer port\n"
|
||||
@@ -200,7 +199,6 @@
|
||||
{"d" , CONFIG_HLP_SOFTS, PARAMFLAG_BOOL, uptr:(uint32_t *)&do_forms, defintval:0, TYPE_INT8, 0}, \
|
||||
{"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, iptr:&opp_enabled, defintval:0, TYPE_INT, 0}, \
|
||||
{"S" , CONFIG_HLP_MSLOTS, PARAMFLAG_BOOL, u8ptr:&exit_missed_slots, defintval:1, TYPE_UINT8, 0}, \
|
||||
{"s" , CONFIG_HLP_SNR, 0, dblptr:&snr_dB, defdblval:25, TYPE_DOUBLE, 0}, \
|
||||
{"numerology" , CONFIG_HLP_NUMEROLOGY, PARAMFLAG_BOOL, iptr:&NUMEROLOGY, defintval:0, TYPE_INT, 0}, \
|
||||
{"parallel-config", CONFIG_HLP_PARALLEL_CMD,0, strptr:(char **)¶llel_config, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{"worker-config", CONFIG_HLP_WORKER_CMD, 0, strptr:(char **)&worker_config, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
@@ -264,9 +262,9 @@ typedef struct {
|
||||
int numerology;
|
||||
unsigned int start_msc;
|
||||
uint32_t clock_source;
|
||||
uint32_t timing_source;
|
||||
uint32_t timing_source;
|
||||
int hw_timing_advance;
|
||||
uint32_t send_dmrs_sync;
|
||||
uint32_t send_dmrs_sync;
|
||||
} softmodem_params_t;
|
||||
|
||||
#define IS_SOFTMODEM_NOS1 ( get_softmodem_optmask() & SOFTMODEM_NOS1_BIT)
|
||||
@@ -285,8 +283,6 @@ uint64_t get_pdcp_optmask(void);
|
||||
extern pthread_cond_t sync_cond;
|
||||
extern pthread_mutex_t sync_mutex;
|
||||
extern int sync_var;
|
||||
extern double snr_dB;
|
||||
|
||||
|
||||
extern uint32_t downlink_frequency[MAX_NUM_CCs][4];
|
||||
extern int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
|
||||
@@ -311,7 +307,7 @@ extern void stop_eNB(int);
|
||||
extern void kill_eNB_proc(int inst);
|
||||
|
||||
// In lte-ru.c
|
||||
extern void init_RU(char*,clock_source_t clock_source,clock_source_t time_source,int send_dmrssync);
|
||||
extern void init_RU(char *,clock_source_t clock_source,clock_source_t time_source,int send_dmrssync);
|
||||
extern void stop_ru(RU_t *ru);
|
||||
extern void init_ru_vnf(void);
|
||||
extern void init_RU_proc(RU_t *ru);
|
||||
@@ -337,7 +333,7 @@ extern void kill_td_thread(PHY_VARS_eNB *);
|
||||
extern void kill_te_thread(PHY_VARS_eNB *);
|
||||
|
||||
extern void RCConfig_sim(void);
|
||||
extern void init_ocm(double,double);
|
||||
extern void init_ocm(void);
|
||||
extern void init_ue_devices(PHY_VARS_UE *);
|
||||
|
||||
PHY_VARS_UE *init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms,
|
||||
|
||||
@@ -323,12 +323,10 @@ static void get_options(void) {
|
||||
int CC_id;
|
||||
int tddflag;
|
||||
char *loopfile=NULL;
|
||||
|
||||
int dumpframe=0;
|
||||
int timingadv;
|
||||
uint8_t nfapi_mode;
|
||||
int simL1flag ;
|
||||
|
||||
set_default_frame_parms(frame_parms);
|
||||
CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP);
|
||||
/* unknown parameters on command line will be checked in main
|
||||
@@ -616,7 +614,7 @@ int main( int argc, char **argv ) {
|
||||
if (config_mod == NULL) {
|
||||
exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
|
||||
}
|
||||
|
||||
|
||||
mode = normal_txrx;
|
||||
memset(&openair0_cfg[0],0,sizeof(openair0_config_t)*MAX_CARDS);
|
||||
set_latency_target();
|
||||
@@ -811,7 +809,7 @@ int main( int argc, char **argv ) {
|
||||
//p_exmimo_config->framing.tdd_config = TXRXSWITCH_TESTRX;
|
||||
|
||||
if (IS_SOFTMODEM_SIML1 ) {
|
||||
init_ocm(snr_dB,0);
|
||||
init_ocm();
|
||||
PHY_vars_UE_g[0][0]->no_timing_correction = 1;
|
||||
}
|
||||
|
||||
|
||||
+159
-217
@@ -63,65 +63,52 @@ sim_t sim;
|
||||
|
||||
void init_ru_devices(void);
|
||||
|
||||
void init_RU(char*,clock_source_t clock_source,clock_source_t time_source,int send_dmrssync);
|
||||
void init_RU(char *,clock_source_t clock_source,clock_source_t time_source,int send_dmrssync);
|
||||
|
||||
void *rfsim_top(void *n_frames);
|
||||
|
||||
void wait_RUs(void)
|
||||
{
|
||||
void wait_RUs(void) {
|
||||
int i;
|
||||
|
||||
// wait for all RUs to be configured over fronthaul
|
||||
pthread_mutex_lock(&RC.ru_mutex);
|
||||
|
||||
|
||||
while (RC.ru_mask>0) {
|
||||
pthread_cond_wait(&RC.ru_cond,&RC.ru_mutex);
|
||||
}
|
||||
|
||||
|
||||
pthread_mutex_unlock(&RC.ru_mutex);
|
||||
|
||||
// copy frame parameters from RU to UEs
|
||||
for (i=0;i<NB_UE_INST;i++) {
|
||||
for (i=0; i<NB_UE_INST; i++) {
|
||||
sim.current_UE_rx_timestamp[i][0] = RC.ru[0]->frame_parms.samples_per_tti + RC.ru[0]->frame_parms.ofdm_symbol_size + RC.ru[0]->frame_parms.nb_prefix_samples0;
|
||||
|
||||
}
|
||||
|
||||
for (int ru_id=0;ru_id<RC.nb_RU;ru_id++) sim.current_ru_rx_timestamp[ru_id][0] = RC.ru[ru_id]->frame_parms.samples_per_tti;
|
||||
for (int ru_id=0; ru_id<RC.nb_RU; ru_id++) sim.current_ru_rx_timestamp[ru_id][0] = RC.ru[ru_id]->frame_parms.samples_per_tti;
|
||||
|
||||
printf("RUs are ready, let's go\n");
|
||||
}
|
||||
|
||||
void wait_eNBs(void)
|
||||
{
|
||||
void wait_eNBs(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void RCConfig_sim(void) {
|
||||
|
||||
paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0};
|
||||
|
||||
// Get num RU instances
|
||||
config_getlist( &RUParamList,NULL,0, NULL);
|
||||
RC.nb_RU = RUParamList.numelt;
|
||||
|
||||
AssertFatal(RC.nb_RU>0,"we need at least 1 RU for simulation\n");
|
||||
printf("returned with %d rus\n",RC.nb_RU);
|
||||
|
||||
init_RU(NULL,internal,internal,0);
|
||||
|
||||
printf("Waiting for RUs to get set up\n");
|
||||
printf("Waiting for RUs to get set up\n");
|
||||
wait_RUs();
|
||||
|
||||
init_ru_devices();
|
||||
|
||||
static int nframes = 100000;
|
||||
|
||||
AssertFatal(0 == pthread_create(&sim.rfsim_thread,
|
||||
NULL,
|
||||
rfsim_top,
|
||||
(void*)&nframes), "");
|
||||
|
||||
(void *)&nframes), "");
|
||||
}
|
||||
|
||||
|
||||
@@ -164,75 +151,64 @@ extern int subframe_ru_mask,subframe_UE_mask;
|
||||
|
||||
|
||||
int ru_trx_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) {
|
||||
|
||||
int ru_id = device->Mod_id;
|
||||
int CC_id = device->CC_id;
|
||||
|
||||
int subframe;
|
||||
int sample_count=0;
|
||||
|
||||
*ptimestamp = sim.last_ru_rx_timestamp[ru_id][CC_id];
|
||||
|
||||
|
||||
LOG_D(SIM,"RU_trx_read nsamps %d TS(%llu,%llu) => subframe %d\n",nsamps,
|
||||
(unsigned long long)sim.current_ru_rx_timestamp[ru_id][CC_id],
|
||||
(unsigned long long)sim.last_ru_rx_timestamp[ru_id][CC_id],
|
||||
(int)((*ptimestamp/RC.ru[ru_id]->frame_parms.samples_per_tti)%10));
|
||||
(int)((*ptimestamp/RC.ru[ru_id]->frame_parms.samples_per_tti)%10));
|
||||
// if we're at a subframe boundary generate UL signals for this ru
|
||||
|
||||
while (sample_count<nsamps) {
|
||||
while (sim.current_ru_rx_timestamp[ru_id][CC_id]<
|
||||
(nsamps+sim.last_ru_rx_timestamp[ru_id][CC_id])) {
|
||||
(nsamps+sim.last_ru_rx_timestamp[ru_id][CC_id])) {
|
||||
LOG_D(SIM,"RU: current TS %"PRIi64", last TS %"PRIi64", sleeping\n",sim.current_ru_rx_timestamp[ru_id][CC_id],sim.last_ru_rx_timestamp[ru_id][CC_id]);
|
||||
usleep(500);
|
||||
}
|
||||
|
||||
|
||||
|
||||
subframe = (sim.last_ru_rx_timestamp[ru_id][CC_id]/RC.ru[ru_id]->frame_parms.samples_per_tti)%10;
|
||||
if (subframe_select(&RC.ru[ru_id]->frame_parms,subframe) != SF_DL || RC.ru[ru_id]->frame_parms.frame_type == FDD) {
|
||||
|
||||
if (subframe_select(&RC.ru[ru_id]->frame_parms,subframe) != SF_DL || RC.ru[ru_id]->frame_parms.frame_type == FDD) {
|
||||
LOG_D(SIM,"RU_trx_read generating UL subframe %d (Ts %llu, current TS %llu)\n",
|
||||
subframe,(unsigned long long)*ptimestamp,
|
||||
(unsigned long long)sim.current_ru_rx_timestamp[ru_id][CC_id]);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SIM_DO_UL_SIGNAL,1);
|
||||
subframe,(unsigned long long)*ptimestamp,
|
||||
(unsigned long long)sim.current_ru_rx_timestamp[ru_id][CC_id]);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SIM_DO_UL_SIGNAL,1);
|
||||
do_UL_sig(&sim,
|
||||
subframe,
|
||||
0, // abstraction_flag
|
||||
&RC.ru[ru_id]->frame_parms,
|
||||
0, // frame is only used for abstraction
|
||||
ru_id,
|
||||
CC_id);
|
||||
subframe,
|
||||
0, // abstraction_flag
|
||||
&RC.ru[ru_id]->frame_parms,
|
||||
0, // frame is only used for abstraction
|
||||
ru_id,
|
||||
CC_id);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SIM_DO_UL_SIGNAL,0);
|
||||
}
|
||||
|
||||
sim.last_ru_rx_timestamp[ru_id][CC_id] += RC.ru[ru_id]->frame_parms.samples_per_tti;
|
||||
sample_count += RC.ru[ru_id]->frame_parms.samples_per_tti;
|
||||
}
|
||||
|
||||
|
||||
return(nsamps);
|
||||
}
|
||||
|
||||
int UE_trx_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc)
|
||||
{
|
||||
int UE_trx_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) {
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SIM_UE_TRX_READ,1);
|
||||
int UE_id = device->Mod_id;
|
||||
int CC_id = device->CC_id;
|
||||
|
||||
int subframe;
|
||||
int sample_count=0;
|
||||
int read_size;
|
||||
int sptti = PHY_vars_UE_g[UE_id][CC_id]->frame_parms.samples_per_tti;
|
||||
|
||||
*ptimestamp = sim.last_UE_rx_timestamp[UE_id][CC_id];
|
||||
|
||||
LOG_D(PHY,"UE %d DL simulation 0: UE_trx_read nsamps %d TS %llu (%llu, offset %d) antenna %d\n",
|
||||
UE_id,
|
||||
nsamps,
|
||||
(unsigned long long)sim.current_UE_rx_timestamp[UE_id][CC_id],
|
||||
(unsigned long long)sim.last_UE_rx_timestamp[UE_id][CC_id],
|
||||
(int)(sim.last_UE_rx_timestamp[UE_id][CC_id]%sptti),
|
||||
cc);
|
||||
|
||||
cc);
|
||||
|
||||
if (nsamps < sptti)
|
||||
read_size = nsamps;
|
||||
@@ -241,55 +217,45 @@ int UE_trx_read(openair0_device *device, openair0_timestamp *ptimestamp, void **
|
||||
|
||||
while (sample_count<nsamps) {
|
||||
LOG_D(SIM,"UE %d: DL simulation 1: UE_trx_read : current TS now %"PRIi64", last TS %"PRIi64"\n",UE_id,sim.current_UE_rx_timestamp[UE_id][CC_id],sim.last_UE_rx_timestamp[UE_id][CC_id]);
|
||||
while (sim.current_UE_rx_timestamp[UE_id][CC_id] <
|
||||
(sim.last_UE_rx_timestamp[UE_id][CC_id]+read_size)) {
|
||||
|
||||
while (sim.current_UE_rx_timestamp[UE_id][CC_id] <
|
||||
(sim.last_UE_rx_timestamp[UE_id][CC_id]+read_size)) {
|
||||
LOG_D(SIM,"UE %d: DL simulation 2: UE_trx_read : current TS %"PRIi64", last TS %"PRIi64", sleeping\n",UE_id,sim.current_UE_rx_timestamp[UE_id][CC_id],sim.last_UE_rx_timestamp[UE_id][CC_id]);
|
||||
usleep(500);
|
||||
}
|
||||
LOG_D(SIM,"UE %d: DL simulation 3: UE_trx_read : current TS now %"PRIi64", last TS %"PRIi64"\n",UE_id,sim.current_UE_rx_timestamp[UE_id][CC_id],sim.last_UE_rx_timestamp[UE_id][CC_id]);
|
||||
|
||||
LOG_D(SIM,"UE %d: DL simulation 3: UE_trx_read : current TS now %"PRIi64", last TS %"PRIi64"\n",UE_id,sim.current_UE_rx_timestamp[UE_id][CC_id],sim.last_UE_rx_timestamp[UE_id][CC_id]);
|
||||
// if we cross a subframe-boundary
|
||||
subframe = (sim.last_UE_rx_timestamp[UE_id][CC_id]/sptti)%10;
|
||||
|
||||
// tell top-level we are busy
|
||||
// tell top-level we are busy
|
||||
pthread_mutex_lock(&sim.subframe_mutex);
|
||||
sim.subframe_UE_mask|=(1<<UE_id);
|
||||
LOG_D(SIM,"Setting UE_id %d mask to busy (%d)\n",UE_id,sim.subframe_UE_mask);
|
||||
pthread_mutex_unlock(&sim.subframe_mutex);
|
||||
|
||||
|
||||
|
||||
LOG_D(PHY,"UE %d: DL simulation 4: UE_trx_read generating DL subframe %d (Ts %llu, current TS %llu,nsamps %d)\n",
|
||||
UE_id,subframe,(unsigned long long)*ptimestamp,
|
||||
(unsigned long long)sim.current_UE_rx_timestamp[UE_id][CC_id],
|
||||
nsamps);
|
||||
|
||||
UE_id,subframe,(unsigned long long)*ptimestamp,
|
||||
(unsigned long long)sim.current_UE_rx_timestamp[UE_id][CC_id],
|
||||
nsamps);
|
||||
LOG_D(SIM,"UE %d: DL simulation 5: Doing DL simulation for %d samples starting in subframe %d at offset %d\n",
|
||||
UE_id,nsamps,subframe,
|
||||
(int)(sim.last_UE_rx_timestamp[UE_id][CC_id]%sptti));
|
||||
|
||||
UE_id,nsamps,subframe,
|
||||
(int)(sim.last_UE_rx_timestamp[UE_id][CC_id]%sptti));
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SIM_DO_DL_SIGNAL,1);
|
||||
do_DL_sig(&sim,
|
||||
subframe,
|
||||
sim.last_UE_rx_timestamp[UE_id][CC_id]%sptti,
|
||||
sptti,
|
||||
0, //abstraction_flag,
|
||||
&PHY_vars_UE_g[UE_id][CC_id]->frame_parms,
|
||||
UE_id,
|
||||
CC_id);
|
||||
subframe,
|
||||
sim.last_UE_rx_timestamp[UE_id][CC_id]%sptti,
|
||||
sptti,
|
||||
0, //abstraction_flag,
|
||||
&PHY_vars_UE_g[UE_id][CC_id]->frame_parms,
|
||||
UE_id,
|
||||
CC_id);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SIM_DO_DL_SIGNAL,0);
|
||||
LOG_D(PHY,"UE %d: DL simulation 6: UE_trx_read @ TS %"PRIi64" (%"PRIi64")=> frame %d, subframe %d\n",
|
||||
UE_id, sim.current_UE_rx_timestamp[UE_id][CC_id],
|
||||
sim.last_UE_rx_timestamp[UE_id][CC_id],
|
||||
(int)((sim.last_UE_rx_timestamp[UE_id][CC_id]/(sptti*10))&1023),
|
||||
subframe);
|
||||
|
||||
UE_id, sim.current_UE_rx_timestamp[UE_id][CC_id],
|
||||
sim.last_UE_rx_timestamp[UE_id][CC_id],
|
||||
(int)((sim.last_UE_rx_timestamp[UE_id][CC_id]/(sptti*10))&1023),
|
||||
subframe);
|
||||
sim.last_UE_rx_timestamp[UE_id][CC_id] += read_size;
|
||||
sample_count += read_size;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SIM_UE_TRX_READ,0);
|
||||
@@ -298,51 +264,45 @@ int UE_trx_read(openair0_device *device, openair0_timestamp *ptimestamp, void **
|
||||
|
||||
|
||||
int ru_trx_write(openair0_device *device,openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) {
|
||||
|
||||
int ru_id = device->Mod_id;
|
||||
|
||||
LTE_DL_FRAME_PARMS *frame_parms = &RC.ru[ru_id]->frame_parms;
|
||||
|
||||
pthread_mutex_lock(&sim.subframe_mutex);
|
||||
LOG_D(SIM,"[TXPATH] ru_trx_write: RU %d mask %d\n",ru_id,sim.subframe_ru_mask);
|
||||
pthread_mutex_unlock(&sim.subframe_mutex);
|
||||
|
||||
pthread_mutex_unlock(&sim.subframe_mutex);
|
||||
// compute amplitude of TX signal from first symbol in subframe
|
||||
// note: assumes that the packet is an entire subframe
|
||||
|
||||
// note: assumes that the packet is an entire subframe
|
||||
sim.ru_amp[ru_id] = 0;
|
||||
for (int aa=0; aa<RC.ru[ru_id]->nb_tx; aa++) {
|
||||
sim.ru_amp[ru_id] += (double)signal_energy((int32_t*)buff[aa],frame_parms->ofdm_symbol_size)/(12*frame_parms->N_RB_DL);
|
||||
}
|
||||
sim.ru_amp[ru_id] = sqrt(sim.ru_amp[ru_id]);
|
||||
|
||||
LOG_D(PHY,"Setting amp for RU %d to %f (%d)\n",ru_id,sim.ru_amp[ru_id], dB_fixed((double)signal_energy((int32_t*)buff[0],frame_parms->ofdm_symbol_size)));
|
||||
for (int aa=0; aa<RC.ru[ru_id]->nb_tx; aa++) {
|
||||
sim.ru_amp[ru_id] += (double)signal_energy((int32_t *)buff[aa],frame_parms->ofdm_symbol_size)/(12*frame_parms->N_RB_DL);
|
||||
}
|
||||
|
||||
sim.ru_amp[ru_id] = sqrt(sim.ru_amp[ru_id]);
|
||||
LOG_D(PHY,"Setting amp for RU %d to %f (%d)\n",ru_id,sim.ru_amp[ru_id], dB_fixed((double)signal_energy((int32_t *)buff[0],frame_parms->ofdm_symbol_size)));
|
||||
// tell top-level we are done
|
||||
pthread_mutex_lock(&sim.subframe_mutex);
|
||||
sim.subframe_ru_mask|=(1<<ru_id);
|
||||
LOG_D(SIM,"Setting RU %d to busy\n",ru_id);
|
||||
pthread_mutex_unlock(&sim.subframe_mutex);
|
||||
|
||||
return(nsamps);
|
||||
}
|
||||
|
||||
int UE_trx_write(openair0_device *device,openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) {
|
||||
|
||||
return(nsamps);
|
||||
}
|
||||
|
||||
void init_ru_devices(){
|
||||
|
||||
|
||||
void init_ru_devices() {
|
||||
module_id_t ru_id;
|
||||
RU_t *ru;
|
||||
|
||||
// allocate memory for RU if not already done
|
||||
if (RC.ru==NULL) RC.ru = (RU_t**)malloc(RC.nb_RU*sizeof(RU_t*));
|
||||
if (RC.ru==NULL) RC.ru = (RU_t **)malloc(RC.nb_RU*sizeof(RU_t *));
|
||||
|
||||
for (ru_id=0;ru_id<RC.nb_RU;ru_id++) {
|
||||
for (ru_id=0; ru_id<RC.nb_RU; ru_id++) {
|
||||
LOG_D(SIM,"Initiaizing rfdevice for RU %d\n",ru_id);
|
||||
if (RC.ru[ru_id]==NULL) RC.ru[ru_id] = (RU_t*)malloc(sizeof(RU_t));
|
||||
|
||||
if (RC.ru[ru_id]==NULL) RC.ru[ru_id] = (RU_t *)malloc(sizeof(RU_t));
|
||||
|
||||
ru = RC.ru[ru_id];
|
||||
ru->rfdevice.Mod_id = ru_id;
|
||||
ru->rfdevice.CC_id = 0;
|
||||
@@ -354,189 +314,171 @@ void init_ru_devices(){
|
||||
ru->rfdevice.trx_set_freq_func = ru_trx_set_freq;
|
||||
ru->rfdevice.trx_set_gains_func = ru_trx_set_gains;
|
||||
sim.last_ru_rx_timestamp[ru_id][0] = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void init_ue_devices(PHY_VARS_UE *UE) {
|
||||
|
||||
AssertFatal(UE!=NULL,"UE context is not allocated\n");
|
||||
printf("Initializing UE %d.%d\n",UE->Mod_id,UE->CC_id);
|
||||
UE->rfdevice.Mod_id = UE->Mod_id;
|
||||
UE->rfdevice.CC_id = UE->CC_id;
|
||||
UE->rfdevice.trx_start_func = UE_trx_start;
|
||||
UE->rfdevice.trx_read_func = UE_trx_read;
|
||||
UE->rfdevice.trx_write_func = UE_trx_write;
|
||||
UE->rfdevice.trx_end_func = UE_trx_end;
|
||||
UE->rfdevice.trx_stop_func = UE_trx_stop;
|
||||
UE->rfdevice.trx_set_freq_func = UE_trx_set_freq;
|
||||
UE->rfdevice.trx_set_gains_func = UE_trx_set_gains;
|
||||
sim.last_UE_rx_timestamp[UE->Mod_id][UE->CC_id] = 0;
|
||||
AssertFatal(UE!=NULL,"UE context is not allocated\n");
|
||||
printf("Initializing UE %d.%d\n",UE->Mod_id,UE->CC_id);
|
||||
UE->rfdevice.Mod_id = UE->Mod_id;
|
||||
UE->rfdevice.CC_id = UE->CC_id;
|
||||
UE->rfdevice.trx_start_func = UE_trx_start;
|
||||
UE->rfdevice.trx_read_func = UE_trx_read;
|
||||
UE->rfdevice.trx_write_func = UE_trx_write;
|
||||
UE->rfdevice.trx_end_func = UE_trx_end;
|
||||
UE->rfdevice.trx_stop_func = UE_trx_stop;
|
||||
UE->rfdevice.trx_set_freq_func = UE_trx_set_freq;
|
||||
UE->rfdevice.trx_set_gains_func = UE_trx_set_gains;
|
||||
sim.last_UE_rx_timestamp[UE->Mod_id][UE->CC_id] = 0;
|
||||
}
|
||||
|
||||
void init_ocm(double snr_dB,double sinr_dB)
|
||||
{
|
||||
void init_ocm(void) {
|
||||
module_id_t UE_id, ru_id;
|
||||
int CC_id;
|
||||
|
||||
randominit(0);
|
||||
set_taus_seed(0);
|
||||
|
||||
|
||||
init_channelmod();
|
||||
double snr_dB = channelmod_get_snr_dB();
|
||||
double sinr_dB = channelmod_get_sinr_dB();
|
||||
init_channel_vars ();//fp, &s_re, &s_im, &r_re, &r_im, &r_re0, &r_im0);
|
||||
|
||||
// initialize channel descriptors
|
||||
LOG_I(PHY,"Initializing channel descriptors (nb_RU %d, nb_UE %d)\n",RC.nb_RU,NB_UE_INST);
|
||||
|
||||
for (ru_id = 0; ru_id < RC.nb_RU; ru_id++) {
|
||||
for (UE_id = 0; UE_id < NB_UE_INST; UE_id++) {
|
||||
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
|
||||
|
||||
LOG_I(PHY,"Initializing channel descriptors (RU %d, UE %d) for N_RB_DL %d\n",ru_id,UE_id,
|
||||
RC.ru[ru_id]->frame_parms.N_RB_DL);
|
||||
sim.RU2UE[ru_id][UE_id][CC_id] =
|
||||
new_channel_desc_scm(RC.ru[ru_id]->nb_tx,
|
||||
PHY_vars_UE_g[UE_id][CC_id]->frame_parms.nb_antennas_rx,
|
||||
AWGN,
|
||||
N_RB2sampling_rate(RC.ru[ru_id]->frame_parms.N_RB_DL),
|
||||
N_RB2channel_bandwidth(RC.ru[ru_id]->frame_parms.N_RB_DL),
|
||||
0.0,
|
||||
0,
|
||||
0);
|
||||
LOG_I(PHY,"Initializing channel descriptors (RU %d, UE %d) for N_RB_DL %d\n",ru_id,UE_id,
|
||||
RC.ru[ru_id]->frame_parms.N_RB_DL);
|
||||
sim.RU2UE[ru_id][UE_id][CC_id] =
|
||||
new_channel_desc_scm(RC.ru[ru_id]->nb_tx,
|
||||
PHY_vars_UE_g[UE_id][CC_id]->frame_parms.nb_antennas_rx,
|
||||
AWGN,
|
||||
N_RB2sampling_rate(RC.ru[ru_id]->frame_parms.N_RB_DL),
|
||||
N_RB2channel_bandwidth(RC.ru[ru_id]->frame_parms.N_RB_DL),
|
||||
0.0,
|
||||
0,
|
||||
0);
|
||||
random_channel(sim.RU2UE[ru_id][UE_id][CC_id],0);
|
||||
LOG_D(OCM,"[SIM] Initializing channel (%s) from UE %d to ru %d\n", "AWGN",UE_id, ru_id);
|
||||
|
||||
|
||||
sim.UE2RU[UE_id][ru_id][CC_id] =
|
||||
new_channel_desc_scm(PHY_vars_UE_g[UE_id][CC_id]->frame_parms.nb_antennas_tx,
|
||||
RC.ru[ru_id]->nb_rx,
|
||||
AWGN,
|
||||
N_RB2sampling_rate(RC.ru[ru_id]->frame_parms.N_RB_UL),
|
||||
N_RB2channel_bandwidth(RC.ru[ru_id]->frame_parms.N_RB_UL),
|
||||
0.0,
|
||||
0,
|
||||
0);
|
||||
|
||||
sim.UE2RU[UE_id][ru_id][CC_id] =
|
||||
new_channel_desc_scm(PHY_vars_UE_g[UE_id][CC_id]->frame_parms.nb_antennas_tx,
|
||||
RC.ru[ru_id]->nb_rx,
|
||||
AWGN,
|
||||
N_RB2sampling_rate(RC.ru[ru_id]->frame_parms.N_RB_UL),
|
||||
N_RB2channel_bandwidth(RC.ru[ru_id]->frame_parms.N_RB_UL),
|
||||
0.0,
|
||||
0,
|
||||
0);
|
||||
random_channel(sim.UE2RU[UE_id][ru_id][CC_id],0);
|
||||
|
||||
// to make channel reciprocal uncomment following line instead of previous. However this only works for SISO at the moment. For MIMO the channel would need to be transposed.
|
||||
//UE2RU[UE_id][ru_id] = RU2UE[ru_id][UE_id];
|
||||
AssertFatal(sim.RU2UE[ru_id][UE_id][CC_id]!=NULL,"RU2UE[%d][%d][%d] is null\n",ru_id,UE_id,CC_id);
|
||||
AssertFatal(sim.UE2RU[UE_id][ru_id][CC_id]!=NULL,"UE2RU[%d][%d][%d] is null\n",UE_id,ru_id,CC_id);
|
||||
|
||||
AssertFatal(sim.RU2UE[ru_id][UE_id][CC_id]!=NULL,"RU2UE[%d][%d][%d] is null\n",ru_id,UE_id,CC_id);
|
||||
AssertFatal(sim.UE2RU[UE_id][ru_id][CC_id]!=NULL,"UE2RU[%d][%d][%d] is null\n",UE_id,ru_id,CC_id);
|
||||
//pathloss: -132.24 dBm/15kHz RE + target SNR - eNB TX power per RE
|
||||
if (ru_id == (UE_id % RC.nb_RU)) {
|
||||
sim.RU2UE[ru_id][UE_id][CC_id]->path_loss_dB = -132.24 + snr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
sim.UE2RU[UE_id][ru_id][CC_id]->path_loss_dB = -132.24 + snr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
} else {
|
||||
sim.RU2UE[ru_id][UE_id][CC_id]->path_loss_dB = -132.24 + sinr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
sim.UE2RU[UE_id][ru_id][CC_id]->path_loss_dB = -132.24 + sinr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
}
|
||||
|
||||
LOG_I(OCM,"Path loss from eNB %d to UE %d (CCid %d)=> %f dB (eNB TX %d, SNR %f)\n",ru_id,UE_id,CC_id,
|
||||
sim.RU2UE[ru_id][UE_id][CC_id]->path_loss_dB,
|
||||
RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower,snr_dB);
|
||||
|
||||
//pathloss: -132.24 dBm/15kHz RE + target SNR - eNB TX power per RE
|
||||
if (ru_id == (UE_id % RC.nb_RU)) {
|
||||
sim.RU2UE[ru_id][UE_id][CC_id]->path_loss_dB = -132.24 + snr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
sim.UE2RU[UE_id][ru_id][CC_id]->path_loss_dB = -132.24 + snr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
} else {
|
||||
sim.RU2UE[ru_id][UE_id][CC_id]->path_loss_dB = -132.24 + sinr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
sim.UE2RU[UE_id][ru_id][CC_id]->path_loss_dB = -132.24 + sinr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
}
|
||||
|
||||
LOG_I(OCM,"Path loss from eNB %d to UE %d (CCid %d)=> %f dB (eNB TX %d, SNR %f)\n",ru_id,UE_id,CC_id,
|
||||
sim.RU2UE[ru_id][UE_id][CC_id]->path_loss_dB,
|
||||
RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower,snr_dB);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void update_ocm(double snr_dB,double sinr_dB)
|
||||
{
|
||||
void update_ocm(double snr_dB,double sinr_dB) {
|
||||
module_id_t UE_id, ru_id;
|
||||
int CC_id;
|
||||
|
||||
for (ru_id = 0; ru_id < RC.nb_RU; ru_id++) {
|
||||
for (UE_id = 0; UE_id < NB_UE_INST; UE_id++) {
|
||||
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
|
||||
AssertFatal(sim.RU2UE[ru_id][UE_id][CC_id]!=NULL,"RU2UE[%d][%d][%d] is null\n",ru_id,UE_id,CC_id);
|
||||
AssertFatal(sim.UE2RU[UE_id][ru_id][CC_id]!=NULL,"UE2RU[%d][%d][%d] is null\n",UE_id,ru_id,CC_id);
|
||||
|
||||
for (ru_id = 0; ru_id < RC.nb_RU; ru_id++) {
|
||||
for (UE_id = 0; UE_id < NB_UE_INST; UE_id++) {
|
||||
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
|
||||
//pathloss: -132.24 dBm/15kHz RE + target SNR - eNB TX power per RE
|
||||
if (ru_id == (UE_id % RC.nb_RU)) {
|
||||
sim.RU2UE[ru_id][UE_id][CC_id]->path_loss_dB = -132.24 + snr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
sim.UE2RU[UE_id][ru_id][CC_id]->path_loss_dB = -132.24 + snr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
} else {
|
||||
sim.RU2UE[ru_id][UE_id][CC_id]->path_loss_dB = -132.24 + sinr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
sim.UE2RU[UE_id][ru_id][CC_id]->path_loss_dB = -132.24 + sinr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
}
|
||||
|
||||
AssertFatal(sim.RU2UE[ru_id][UE_id][CC_id]!=NULL,"RU2UE[%d][%d][%d] is null\n",ru_id,UE_id,CC_id);
|
||||
AssertFatal(sim.UE2RU[UE_id][ru_id][CC_id]!=NULL,"UE2RU[%d][%d][%d] is null\n",UE_id,ru_id,CC_id);
|
||||
//pathloss: -132.24 dBm/15kHz RE + target SNR - eNB TX power per RE
|
||||
if (ru_id == (UE_id % RC.nb_RU)) {
|
||||
sim.RU2UE[ru_id][UE_id][CC_id]->path_loss_dB = -132.24 + snr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
sim.UE2RU[UE_id][ru_id][CC_id]->path_loss_dB = -132.24 + snr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
} else {
|
||||
sim.RU2UE[ru_id][UE_id][CC_id]->path_loss_dB = -132.24 + sinr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
sim.UE2RU[UE_id][ru_id][CC_id]->path_loss_dB = -132.24 + sinr_dB - RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower;
|
||||
}
|
||||
|
||||
LOG_D(OCM,"Path loss from eNB %d to UE %d (CCid %d)=> %f dB (eNB TX %d, SNR %f)\n",ru_id,UE_id,CC_id,
|
||||
sim.RU2UE[ru_id][UE_id][CC_id]->path_loss_dB,
|
||||
RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower,snr_dB);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_D(OCM,"Path loss from eNB %d to UE %d (CCid %d)=> %f dB (eNB TX %d, SNR %f)\n",ru_id,UE_id,CC_id,
|
||||
sim.RU2UE[ru_id][UE_id][CC_id]->path_loss_dB,
|
||||
RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower,snr_dB);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void init_channel_vars(void)
|
||||
{
|
||||
|
||||
void init_channel_vars(void) {
|
||||
int i;
|
||||
|
||||
memset(sim.RU_output_mask,0,sizeof(int)*NUMBER_OF_UE_MAX);
|
||||
for (i=0;i<NB_UE_INST;i++)
|
||||
|
||||
for (i=0; i<NB_UE_INST; i++)
|
||||
pthread_mutex_init(&sim.RU_output_mutex[i],NULL);
|
||||
|
||||
memset(sim.UE_output_mask,0,sizeof(int)*NUMBER_OF_RU_MAX);
|
||||
for (i=0;i<RC.nb_RU;i++)
|
||||
pthread_mutex_init(&sim.UE_output_mutex[i],NULL);
|
||||
|
||||
for (i=0; i<RC.nb_RU; i++)
|
||||
pthread_mutex_init(&sim.UE_output_mutex[i],NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void *rfsim_top(void *n_frames) {
|
||||
|
||||
|
||||
wait_sync("rfsim_top");
|
||||
printf("Running rfsim with %d frames\n",*(int *)n_frames);
|
||||
|
||||
|
||||
printf("Running rfsim with %d frames\n",*(int*)n_frames);
|
||||
for (int frame = 0;
|
||||
frame < *(int*)n_frames;
|
||||
frame < *(int *)n_frames;
|
||||
frame++) {
|
||||
|
||||
for (int sf = 0; sf < 10; sf++) {
|
||||
int CC_id=0;
|
||||
int all_done=0;
|
||||
while (all_done==0) {
|
||||
|
||||
pthread_mutex_lock(&sim.subframe_mutex);
|
||||
|
||||
int subframe_ru_mask_local = (subframe_select(&RC.ru[0]->frame_parms,(sf+4)%10)!=SF_UL) ? sim.subframe_ru_mask : ((1<<RC.nb_RU)-1);
|
||||
int subframe_UE_mask_local = (RC.ru[0]->frame_parms.frame_type == FDD || subframe_select(&RC.ru[0]->frame_parms,(sf+4)%10)!=SF_DL) ? sim.subframe_UE_mask : ((1<<NB_UE_INST)-1);
|
||||
pthread_mutex_unlock(&sim.subframe_mutex);
|
||||
LOG_D(SIM,"Frame %d, Subframe %d, NB_RU %d, NB_UE %d: Checking masks %x,%x\n",frame,sf,RC.nb_RU,NB_UE_INST,subframe_ru_mask_local,subframe_UE_mask_local);
|
||||
if ((subframe_ru_mask_local == ((1<<RC.nb_RU)-1)) &&
|
||||
(subframe_UE_mask_local == ((1<<NB_UE_INST)-1))) all_done=1;
|
||||
else usleep(1500);
|
||||
while (all_done==0) {
|
||||
pthread_mutex_lock(&sim.subframe_mutex);
|
||||
int subframe_ru_mask_local = (subframe_select(&RC.ru[0]->frame_parms,(sf+4)%10)!=SF_UL) ? sim.subframe_ru_mask : ((1<<RC.nb_RU)-1);
|
||||
int subframe_UE_mask_local = (RC.ru[0]->frame_parms.frame_type == FDD || subframe_select(&RC.ru[0]->frame_parms,(sf+4)%10)!=SF_DL) ? sim.subframe_UE_mask : ((1<<NB_UE_INST)-1);
|
||||
pthread_mutex_unlock(&sim.subframe_mutex);
|
||||
LOG_D(SIM,"Frame %d, Subframe %d, NB_RU %d, NB_UE %d: Checking masks %x,%x\n",frame,sf,RC.nb_RU,NB_UE_INST,subframe_ru_mask_local,subframe_UE_mask_local);
|
||||
|
||||
if ((subframe_ru_mask_local == ((1<<RC.nb_RU)-1)) &&
|
||||
(subframe_UE_mask_local == ((1<<NB_UE_INST)-1))) all_done=1;
|
||||
else usleep(1500);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//clear subframe masks for next round
|
||||
pthread_mutex_lock(&sim.subframe_mutex);
|
||||
sim.subframe_ru_mask=0;
|
||||
sim.subframe_UE_mask=0;
|
||||
pthread_mutex_unlock(&sim.subframe_mutex);
|
||||
|
||||
|
||||
// increment timestamps
|
||||
for (int ru_id=0;ru_id<RC.nb_RU;ru_id++) {
|
||||
sim.current_ru_rx_timestamp[ru_id][CC_id] += RC.ru[ru_id]->frame_parms.samples_per_tti;
|
||||
LOG_D(SIM,"RU %d/%d: TS %"PRIi64"\n",ru_id,CC_id,sim.current_ru_rx_timestamp[ru_id][CC_id]);
|
||||
for (int ru_id=0; ru_id<RC.nb_RU; ru_id++) {
|
||||
sim.current_ru_rx_timestamp[ru_id][CC_id] += RC.ru[ru_id]->frame_parms.samples_per_tti;
|
||||
LOG_D(SIM,"RU %d/%d: TS %"PRIi64"\n",ru_id,CC_id,sim.current_ru_rx_timestamp[ru_id][CC_id]);
|
||||
}
|
||||
for (int UE_inst = 0; UE_inst<NB_UE_INST;UE_inst++) {
|
||||
sim.current_UE_rx_timestamp[UE_inst][CC_id] += PHY_vars_UE_g[UE_inst][CC_id]->frame_parms.samples_per_tti;
|
||||
LOG_D(SIM,"UE %d/%d: TS %"PRIi64"\n",UE_inst,CC_id,sim.current_UE_rx_timestamp[UE_inst][CC_id]);
|
||||
|
||||
for (int UE_inst = 0; UE_inst<NB_UE_INST; UE_inst++) {
|
||||
sim.current_UE_rx_timestamp[UE_inst][CC_id] += PHY_vars_UE_g[UE_inst][CC_id]->frame_parms.samples_per_tti;
|
||||
LOG_D(SIM,"UE %d/%d: TS %"PRIi64"\n",UE_inst,CC_id,sim.current_UE_rx_timestamp[UE_inst][CC_id]);
|
||||
}
|
||||
if (oai_exit == 1) return((void*)NULL);
|
||||
|
||||
if (oai_exit == 1) return((void *)NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return((void*)NULL);
|
||||
return((void *)NULL);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "PHY/defs_UE.h"
|
||||
#include "PHY/defs_eNB.h"
|
||||
|
||||
void init_ocm(double snr_dB,double sinr_dB);
|
||||
void init_ocm(void);
|
||||
|
||||
void update_ocm(double snr_dB,double sinr_dB);
|
||||
|
||||
@@ -37,4 +37,4 @@ void update_ocm(double snr_dB,double sinr_dB);
|
||||
|
||||
void init_channel_vars(void);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user