merge of develop&develop-nr
This commit is contained in:
@@ -420,7 +420,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,63 +1,81 @@
|
||||
#General
|
||||
This is an RF simulator that allows to test OAI without an RF board.
|
||||
# General
|
||||
This is an RF simulator that allows to test OAI without an RF board. It replaces an actual RF board driver.
|
||||
|
||||
It replaces an actual RF board driver.
|
||||
As much as possible, it works like an RF board, but not in real-time: It can run faster than real-time if there is enough CPU, or slower (it is CPU-bound instead of real-time RF sampling-bound).
|
||||
|
||||
As much as possible, it works like an 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](../../../doc/BUILD.md) script
|
||||
The RF simulator is implemented as an OAI device and always built when you build the OAI eNB or the OAI UE.
|
||||
|
||||
## From build_oai
|
||||
You can build it the same way, and together with actual RF driver
|
||||
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.Rel15.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 using 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_build_oai_script>/build
|
||||
cd <path to oai sources>/openairinterface5g/cmake_targets/ran_build/build
|
||||
make rfsimulator
|
||||
```
|
||||
Then, you can use it freely
|
||||
This is equivalent to using `-w SIMU` when running the `build_oai` script.
|
||||
|
||||
# Usage
|
||||
Setting the env variable RFSIMULATOR enables the RF board simulator. It should be set to "server" in the eNB or gNB.
|
||||
To use the RF simulator 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, and 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 behaves 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
|
||||
example:
|
||||
For the UE, it should be set to the IP address of the eNB. For example:
|
||||
```bash
|
||||
sudo RFSIMULATOR=192.168.2.200 ./lte-uesoftmodem -C 2685000000 -r 50
|
||||
```
|
||||
For the eNodeB, use a valid configuration file setup for USRP board tests and start the softmodem as usual, **but** adding the `--rfsim` option.
|
||||
|
||||
For the eNB, use a valid configuration file setup for the USRP board tests and start the softmodem as usual, **but**, adding the `--rfsim` option.
|
||||
```bash
|
||||
sudo RFSIMULATOR=enb ./lte-softmodem -O <config file> --rfsim
|
||||
```
|
||||
|
||||
Except this, the UE and the eNB can be used as if the RF is real
|
||||
|
||||
If you reach 'RA not active' on UE, be careful to generate a valid SIM
|
||||
Except this, the UE and the eNB can be used as if 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.
|
||||
```bash
|
||||
$OPENAIR_DIR/targets/bin/conf2uedata -c $OPENAIR_DIR/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf -o .
|
||||
```
|
||||
|
||||
## 5G case
|
||||
After regular build, add the simulation driver
|
||||
(don't use ./build_oai -w SIMU until we merge 4G and 5G branches)
|
||||
|
||||
The 5G RF simulator will be aligned with the 4G as the efforts for merging the 5G specific branches into the develop make progresses.
|
||||
|
||||
After regular build, add the simulation driver (do not use ./build_oai -w SIMU until 4G and 5G branches are merged).
|
||||
```bash
|
||||
cd ran_build/build
|
||||
make rfsimulator
|
||||
@@ -77,46 +95,40 @@ sudo RFSIMULATOR=127.0.0.1 ./nr-uesoftmodem --numerology 1 -r 106 -C 3510000000
|
||||
|
||||
Of course, set the gNB machine IP address if the UE and the gNB are not on the same machine.
|
||||
|
||||
In UE, you can add "-d" to get the softscope
|
||||
In the UE, you can add `-d` option to get the softscope.
|
||||
|
||||
### Store and replay
|
||||
|
||||
You can store emitted I/Q samples:
|
||||
You can store emitted I/Q samples. If you set the option `saviq`, the simulator will write all the I/Q samples into this file. Then, you can replay with the executable `replay_node`.
|
||||
|
||||
If you set the environment variable: saveIQfile to a file name
|
||||
The simulator will write all IQ samples into this file
|
||||
|
||||
Then, you can replay with the executable "replay_node"
|
||||
|
||||
First compile it, as the other binaries
|
||||
```
|
||||
First compile it like other binaries:
|
||||
```bash
|
||||
make replay_node
|
||||
```
|
||||
You can use this binary as I/Q data source to feed whatever UE or NB with recorded I/Q samples.
|
||||
You can use this binary as I/Q data source to feed whatever UE or gNB with recorded I/Q samples.
|
||||
|
||||
The file format is successive blocks of a header followed by the I/Q array.
|
||||
If you have existing stored I/Q, you can adpat the tool "replay_node" to convert your format to the rfsimulator format.
|
||||
The file format is successive blocks of a header followed by the I/Q array. If you have existing stored I/Q, you can adapt the tool `replay_node` to convert your format to the rfsimulator format.
|
||||
|
||||
The format intend to be compatible with the OAI store/replay feature on USRP
|
||||
The format intends 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 the current version all channel parameters are set depending on the model name via a call to:
|
||||
```bash
|
||||
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
|
||||
0, // maybe used for TA
|
||||
0); // path_loss in dB
|
||||
0, // maybe used for TA
|
||||
0); // path_loss in dB
|
||||
```
|
||||
Only the input noise can be changed on command line with the `-s` parameter.
|
||||
|
||||
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. `-s` is a shortcut to `channelmod.s`. It is expected to enhance the channel modelization flexibility by the addition of more parameters in the channelmod section.
|
||||
|
||||
With path loss = 0 set "-s 5" to see a little noise.
|
||||
|
||||
## Caveats
|
||||
Still issues in power control: txgain, rxgain are not used
|
||||
# Caveats
|
||||
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,91 +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];
|
||||
@@ -165,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) {
|
||||
@@ -213,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 {
|
||||
@@ -267,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;
|
||||
@@ -277,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 }
|
||||
};
|
||||
@@ -299,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 }
|
||||
};
|
||||
@@ -307,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");
|
||||
@@ -327,15 +320,15 @@ 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)
|
||||
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);
|
||||
|
||||
samplesBlockHeader_t header= {t->typeStamp, nsamps, nbAnt, timestamp};
|
||||
fullwrite(b->conn_sock,&header, sizeof(header), t);
|
||||
fullwrite(b->conn_sock, &header, sizeof(header), t);
|
||||
sample_t tmpSamples[nsamps][nbAnt];
|
||||
|
||||
for(int a=0; a<nbAnt; a++) {
|
||||
@@ -488,39 +481,48 @@ 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++) {
|
||||
for (int sock=0; sock<FD_SETSIZE; 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);
|
||||
// The caller modem (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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,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...
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,33 +618,9 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
// --log_config.hw_log_level debug
|
||||
// (for phy layer, replace "hw" by "phy")
|
||||
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);
|
||||
|
||||
@@ -230,6 +230,7 @@ eNBs =
|
||||
|
||||
|
||||
pdsch_maxNumRepetitionCEmodeA_r13 = "r16"; #0
|
||||
pusch_repetitionLevelCEmodeA_r13 = "l1"; #0
|
||||
#pdsch_maxNumRepetitionCEmodeB_r13 = "r384"; # NULL - 2
|
||||
|
||||
pusch_maxNumRepetitionCEmodeA_r13 = "r8"; #0
|
||||
|
||||
@@ -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"
|
||||
@@ -197,7 +196,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}, \
|
||||
{"emulate-rf" , CONFIG_HLP_EMULATE_RF, PARAMFLAG_BOOL, iptr:&EMULATE_RF, defintval:0, TYPE_INT, 0}, \
|
||||
{"parallel-config", CONFIG_HLP_PARALLEL_CMD,0, strptr:(char **)¶llel_config, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
@@ -308,9 +306,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)
|
||||
@@ -329,7 +327,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];
|
||||
@@ -339,7 +336,7 @@ extern uint8_t exit_missed_slots;
|
||||
extern uint64_t num_missed_slots; // counter for the number of missed slots
|
||||
|
||||
extern int oaisim_flag;
|
||||
extern volatile int oai_exit;
|
||||
extern volatile int oai_exit;
|
||||
|
||||
extern openair0_config_t openair0_cfg[MAX_CARDS];
|
||||
extern pthread_cond_t sync_cond;
|
||||
@@ -351,8 +348,7 @@ extern double cpuf;
|
||||
// In lte-enb.c
|
||||
extern void stop_eNB(int);
|
||||
extern void kill_eNB_proc(int inst);
|
||||
extern void init_eNB(int single_thread_flag,
|
||||
int wait_for_sync);
|
||||
extern void init_eNB(int single_thread_flag, int wait_for_sync);
|
||||
|
||||
// In lte-ru.c
|
||||
extern void stop_ru(RU_t *ru);
|
||||
@@ -361,15 +357,10 @@ extern void init_RU_proc(RU_t *ru);
|
||||
extern void stop_RU(int nb_ru);
|
||||
extern void kill_RU_proc(RU_t *ru);
|
||||
extern void set_function_spec_param(RU_t *ru);
|
||||
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);
|
||||
|
||||
// In lte-ue.c
|
||||
extern int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue,
|
||||
openair0_config_t *openair0_cfg);
|
||||
|
||||
extern int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg);
|
||||
extern void fill_ue_band_info(void);
|
||||
|
||||
extern void init_UE(int nb_inst,
|
||||
@@ -384,11 +375,7 @@ extern void init_UE(int nb_inst,
|
||||
int txpowermax,
|
||||
LTE_DL_FRAME_PARMS *fp);
|
||||
|
||||
extern void init_thread(int sched_runtime,
|
||||
int sched_deadline,
|
||||
int sched_fifo,
|
||||
cpu_set_t *cpuset,
|
||||
char *name);
|
||||
extern void init_thread(int sched_runtime, int sched_deadline, int sched_fifo, cpu_set_t *cpuset, char *name);
|
||||
|
||||
extern void reset_opp_meas(void);
|
||||
extern void print_opp_meas(void);
|
||||
@@ -399,24 +386,17 @@ 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,
|
||||
uint8_t UE_id,
|
||||
uint8_t abstraction_flag);
|
||||
PHY_VARS_UE *init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms, uint8_t UE_id, uint8_t abstraction_flag);
|
||||
|
||||
void init_eNB_afterRU(void);
|
||||
extern int stop_L1L2(module_id_t enb_id);
|
||||
extern int restart_L1L2(module_id_t enb_id);
|
||||
|
||||
extern void init_UE_stub_single_thread(int nb_inst,
|
||||
int eMBMS_active,
|
||||
int uecap_xer_in,
|
||||
char *emul_iface);
|
||||
extern void init_UE_stub_single_thread(int nb_inst, int eMBMS_active, int uecap_xer_in, char *emul_iface);
|
||||
|
||||
extern PHY_VARS_UE *init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms,
|
||||
uint8_t UE_id,
|
||||
uint8_t abstraction_flag);
|
||||
extern PHY_VARS_UE *init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms, uint8_t UE_id, uint8_t abstraction_flag);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -318,7 +318,6 @@ static void get_options(void) {
|
||||
int CC_id;
|
||||
int tddflag = 0;
|
||||
char *loopfile = NULL;
|
||||
|
||||
int dumpframe = 0;
|
||||
int timingadv = 0;
|
||||
uint8_t nfapi_mode = NFAPI_MONOLITHIC;
|
||||
@@ -592,7 +591,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();
|
||||
@@ -792,7 +791,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;
|
||||
}
|
||||
|
||||
|
||||
+172
-224
@@ -64,65 +64,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), "");
|
||||
}
|
||||
|
||||
|
||||
@@ -165,75 +152,65 @@ 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) {
|
||||
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;
|
||||
@@ -242,49 +219,43 @@ 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;
|
||||
}
|
||||
@@ -295,245 +266,222 @@ 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));
|
||||
ru = RC.ru[ru_id];
|
||||
ru->rfdevice.Mod_id = ru_id;
|
||||
ru->rfdevice.CC_id = 0;
|
||||
ru->rfdevice.trx_start_func = ru_trx_start;
|
||||
ru->rfdevice.trx_read_func = ru_trx_read;
|
||||
ru->rfdevice.trx_write_func = ru_trx_write;
|
||||
ru->rfdevice.trx_end_func = ru_trx_end;
|
||||
ru->rfdevice.trx_stop_func = ru_trx_stop;
|
||||
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;
|
||||
|
||||
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;
|
||||
ru->rfdevice.trx_start_func = ru_trx_start;
|
||||
ru->rfdevice.trx_read_func = ru_trx_read;
|
||||
ru->rfdevice.trx_write_func = ru_trx_write;
|
||||
ru->rfdevice.trx_end_func = ru_trx_end;
|
||||
ru->rfdevice.trx_stop_func = ru_trx_stop;
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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++) {
|
||||
|
||||
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;
|
||||
}
|
||||
//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++) {
|
||||
|
||||
for (int frame = 0; 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