rfsimulator: add support to simulate a long propagation delay
Add the option `--rfsimulator.prop_delay` to specify the simulated receive-path (gNB: UL, UE: DL) propagation delay in ms. This option can be used e.g. to simulate a simple GEO satellite channel by specifying `--rfsimulator.prop_delay 238.74` to both, the gNB and the UE. This is part of the work developed by Fraunhofer IIS within the ESA-funded project 5G-GOA (https://connectivity.esa.int/projects/5ggoa).
This commit is contained in:
@@ -141,7 +141,7 @@ int config_setdefault_int64(configmodule_interface_t *cfg, paramdef_t *cfgoption
|
|||||||
config_check_valptr(cfg, cfgoptions, sizeof(*cfgoptions->i64ptr), 1);
|
config_check_valptr(cfg, cfgoptions, sizeof(*cfgoptions->i64ptr), 1);
|
||||||
|
|
||||||
if (((cfgoptions->paramflags & PARAMFLAG_MANDATORY) == 0)) {
|
if (((cfgoptions->paramflags & PARAMFLAG_MANDATORY) == 0)) {
|
||||||
*(cfgoptions->u64ptr) = cfgoptions->defuintval;
|
*(cfgoptions->u64ptr) = cfgoptions->defint64val;
|
||||||
status=1;
|
status=1;
|
||||||
printf_params(cfg,
|
printf_params(cfg,
|
||||||
"[CONFIG] %s.%s set to default value %llu\n",
|
"[CONFIG] %s.%s set to default value %llu\n",
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ static unsigned int max_chan;
|
|||||||
static channel_desc_t **defined_channels;
|
static channel_desc_t **defined_channels;
|
||||||
static char *modellist_name;
|
static char *modellist_name;
|
||||||
|
|
||||||
|
|
||||||
void fill_channel_desc(channel_desc_t *chan_desc,
|
void fill_channel_desc(channel_desc_t *chan_desc,
|
||||||
uint8_t nb_tx,
|
uint8_t nb_tx,
|
||||||
uint8_t nb_rx,
|
uint8_t nb_rx,
|
||||||
@@ -92,9 +91,10 @@ void fill_channel_desc(channel_desc_t *chan_desc,
|
|||||||
double aoa,
|
double aoa,
|
||||||
double forgetting_factor,
|
double forgetting_factor,
|
||||||
double max_Doppler,
|
double max_Doppler,
|
||||||
int32_t channel_offset,
|
uint64_t channel_offset,
|
||||||
double path_loss_dB,
|
double path_loss_dB,
|
||||||
uint8_t random_aoa) {
|
uint8_t random_aoa)
|
||||||
|
{
|
||||||
uint16_t i,j;
|
uint16_t i,j;
|
||||||
double delta_tau;
|
double delta_tau;
|
||||||
LOG_I(OCM,"[CHANNEL] Getting new channel descriptor, nb_tx %d, nb_rx %d, nb_taps %d, channel_length %d\n",
|
LOG_I(OCM,"[CHANNEL] Getting new channel descriptor, nb_tx %d, nb_rx %d, nb_taps %d, channel_length %d\n",
|
||||||
@@ -568,7 +568,7 @@ channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
|
|||||||
double maxDoppler,
|
double maxDoppler,
|
||||||
const corr_level_t corr_level,
|
const corr_level_t corr_level,
|
||||||
double forgetting_factor,
|
double forgetting_factor,
|
||||||
int32_t channel_offset,
|
uint64_t channel_offset,
|
||||||
double path_loss_dB,
|
double path_loss_dB,
|
||||||
float noise_power_dB)
|
float noise_power_dB)
|
||||||
{
|
{
|
||||||
@@ -2063,8 +2063,12 @@ static void display_channelmodel(channel_desc_t *cd,int debug, telnet_printfunc_
|
|||||||
prnt("nb_tx: %i nb_rx: %i taps: %i bandwidth: %lf sampling: %lf\n",cd->nb_tx, cd->nb_rx, cd->nb_taps, cd->channel_bandwidth, cd->sampling_rate);
|
prnt("nb_tx: %i nb_rx: %i taps: %i bandwidth: %lf sampling: %lf\n",cd->nb_tx, cd->nb_rx, cd->nb_taps, cd->channel_bandwidth, cd->sampling_rate);
|
||||||
prnt("channel length: %i Max path delay: %lf ricean fact.: %lf angle of arrival: %lf (randomized:%s)\n",
|
prnt("channel length: %i Max path delay: %lf ricean fact.: %lf angle of arrival: %lf (randomized:%s)\n",
|
||||||
cd->channel_length, cd->Td, cd->ricean_factor, cd->aoa, (cd->random_aoa?"Yes":"No"));
|
cd->channel_length, cd->Td, cd->ricean_factor, cd->aoa, (cd->random_aoa?"Yes":"No"));
|
||||||
prnt("max Doppler: %lf path loss: %lf noise: %lf rchannel offset: %i forget factor; %lf\n",
|
prnt("max Doppler: %lf path loss: %lf noise: %lf rchannel offset: %lu forget factor; %lf\n",
|
||||||
cd->max_Doppler, cd->path_loss_dB, cd->noise_power_dB, cd->channel_offset, cd->forgetting_factor);
|
cd->max_Doppler,
|
||||||
|
cd->path_loss_dB,
|
||||||
|
cd->noise_power_dB,
|
||||||
|
cd->channel_offset,
|
||||||
|
cd->forgetting_factor);
|
||||||
prnt("Initial phase: %lf nb_path: %i \n",
|
prnt("Initial phase: %lf nb_path: %i \n",
|
||||||
cd->ip, cd->nb_paths);
|
cd->ip, cd->nb_paths);
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ typedef struct {
|
|||||||
///path loss including shadow fading in dB
|
///path loss including shadow fading in dB
|
||||||
double path_loss_dB;
|
double path_loss_dB;
|
||||||
///additional delay of channel in samples.
|
///additional delay of channel in samples.
|
||||||
int32_t channel_offset;
|
uint64_t channel_offset;
|
||||||
float noise_power_dB;
|
float noise_power_dB;
|
||||||
///This parameter (0...1) allows for simple 1st order temporal variation. 0 means a new channel every call, 1 means keep channel constant all the time
|
///This parameter (0...1) allows for simple 1st order temporal variation. 0 means a new channel every call, 1 means keep channel constant all the time
|
||||||
double forgetting_factor;
|
double forgetting_factor;
|
||||||
@@ -307,7 +307,6 @@ typedef struct {
|
|||||||
double ru_amp[NUMBER_OF_RU_MAX];
|
double ru_amp[NUMBER_OF_RU_MAX];
|
||||||
} sim_t;
|
} sim_t;
|
||||||
|
|
||||||
|
|
||||||
channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
|
channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
|
||||||
uint8_t nb_rx,
|
uint8_t nb_rx,
|
||||||
SCM_t channel_model,
|
SCM_t channel_model,
|
||||||
@@ -318,7 +317,7 @@ channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
|
|||||||
double maxDoppler,
|
double maxDoppler,
|
||||||
const corr_level_t corr_level,
|
const corr_level_t corr_level,
|
||||||
double forgetting_factor,
|
double forgetting_factor,
|
||||||
int32_t channel_offset,
|
uint64_t channel_offset,
|
||||||
double path_loss_dB,
|
double path_loss_dB,
|
||||||
float noise_power_dB);
|
float noise_power_dB);
|
||||||
|
|
||||||
|
|||||||
@@ -73,10 +73,11 @@ The RF simulator is using the configuration module, and its parameters are defin
|
|||||||
|:--------------------- |:-------------------------------------------------------------------------------|----: |
|
|:--------------------- |:-------------------------------------------------------------------------------|----: |
|
||||||
|`--rfsimulator.serveraddr <addr>`| ip address to connect to, or `server` to behave as a tcp server | 127.0.0.1 |
|
|`--rfsimulator.serveraddr <addr>`| ip address to connect to, or `server` to behave as a tcp server | 127.0.0.1 |
|
||||||
|`--rfsimulator.serverport <port>`| port number to connect to or to listen on (eNB, which behaves as a tcp server) | 4043 |
|
|`--rfsimulator.serverport <port>`| port number to connect to or to listen on (eNB, which behaves as a tcp server) | 4043 |
|
||||||
| `--rfsimulator.options` | list of comma separated run-time options, two are supported: `chanmod`, `saviq`| all options disabled |
|
|`--rfsimulator.options` | list of comma separated run-time options, two are supported: `chanmod`, `saviq`| all options disabled |
|
||||||
| `--rfsimulator.options saviq` | store IQs to a file for future replay | disabled |
|
|`--rfsimulator.options saviq` | store IQs to a file for future replay | disabled |
|
||||||
|`--rfsimulator.options chanmod` | enable the channel model | disabled |
|
|`--rfsimulator.options chanmod` | enable the channel model | disabled |
|
||||||
|`--rfsimulator.IQfile <file>` | path to a file to store the IQ samples to (only with `saviq`) | `/tmp/rfsimulator.iqs` |
|
|`--rfsimulator.IQfile <file>` | path to a file to store the IQ samples to (only with `saviq`) | `/tmp/rfsimulator.iqs` |
|
||||||
|
|`--rfsimulator.prop_delay` | simulated receive-path (gNB: UL, UE: DL) propagation delay in ms | 0 |
|
||||||
|`--rfsimulator.wait_timeout` | wait timeout when no UE is connected | 1 |
|
|`--rfsimulator.wait_timeout` | wait timeout when no UE is connected | 1 |
|
||||||
|
|
||||||
Please refer to this document [`SIMULATION/TOOLS/DOC/channel_simulation.md`](../../openair1/SIMULATION/TOOLS/DOC/channel_simulation.md) for information about using the RFSimulator options to run the simulator with a channel model.
|
Please refer to this document [`SIMULATION/TOOLS/DOC/channel_simulation.md`](../../openair1/SIMULATION/TOOLS/DOC/channel_simulation.md) for information about using the RFSimulator options to run the simulator with a channel model.
|
||||||
@@ -152,6 +153,24 @@ The format intends to be compatible with the OAI store/replay feature on USRP.
|
|||||||
|
|
||||||
Please refer to this document [`channel_simulation.md`](../../openair1/SIMULATION/TOOLS/DOC/channel_simulation.md) to get familiar with channel simulation in RFSIM and to see the list of commands for real-time usage with telnet.
|
Please refer to this document [`channel_simulation.md`](../../openair1/SIMULATION/TOOLS/DOC/channel_simulation.md) to get familiar with channel simulation in RFSIM and to see the list of commands for real-time usage with telnet.
|
||||||
|
|
||||||
|
## How to simulate a simple GEO satellite channel model
|
||||||
|
|
||||||
|
A simple channel model for satellites on a geostationary orbit (GEO) simulates simply one line-of-sight propagation channel.
|
||||||
|
|
||||||
|
The most basic version is to simply simulate a constant propagation delay, without any other effects.
|
||||||
|
|
||||||
|
In case of a transparent GEO satellite, the minumum one-way propagation delay (DL: gNB -> satellite -> UE, or UL: UE -> satellite -> gNB) is 238.74 ms.
|
||||||
|
|
||||||
|
So, additionally to other parameters, this parameter should be given when executing the gNB and the UE executables:
|
||||||
|
|
||||||
|
```
|
||||||
|
--rfsimulator.prop_delay 238.74
|
||||||
|
```
|
||||||
|
|
||||||
|
Note:
|
||||||
|
|
||||||
|
To successfully establish a connection with such a GEO satellite channel, both gNB and UE need to have the NTN support configured.
|
||||||
|
|
||||||
# Caveats
|
# Caveats
|
||||||
|
|
||||||
There are issues in power control: txgain/rxgain setting is not supported.
|
There are issues in power control: txgain/rxgain setting is not supported.
|
||||||
|
|||||||
@@ -66,7 +66,7 @@
|
|||||||
// The default value is chosen for 10ms buffering which makes 23040*20 = 460800 samples
|
// The default value is chosen for 10ms buffering which makes 23040*20 = 460800 samples
|
||||||
// The previous value is kept below in comment it was computed for 100ms 1x 20MHz
|
// The previous value is kept below in comment it was computed for 100ms 1x 20MHz
|
||||||
// #define CirSize 6144000 // 100ms SiSo 20MHz LTE
|
// #define CirSize 6144000 // 100ms SiSo 20MHz LTE
|
||||||
#define CirSize 460800 // 10ms SiSo 40Mhz 3/4 sampling NR78 FR1
|
#define minCirSize 460800 // 10ms SiSo 40Mhz 3/4 sampling NR78 FR1
|
||||||
#define sampleToByte(a,b) ((a)*(b)*sizeof(sample_t))
|
#define sampleToByte(a,b) ((a)*(b)*sizeof(sample_t))
|
||||||
#define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b)))
|
#define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b)))
|
||||||
|
|
||||||
@@ -114,7 +114,8 @@ typedef enum { SIMU_ROLE_SERVER = 1, SIMU_ROLE_CLIENT } simuRole;
|
|||||||
{"modelname", "<channel model name>\n", simOpt, .strptr=&modelname, .defstrval="AWGN", TYPE_STRING, 0 },\
|
{"modelname", "<channel model name>\n", simOpt, .strptr=&modelname, .defstrval="AWGN", TYPE_STRING, 0 },\
|
||||||
{"ploss", "<channel path loss in dB>\n", simOpt, .dblptr=&(rfsimulator->chan_pathloss), .defdblval=0, TYPE_DOUBLE, 0 },\
|
{"ploss", "<channel path loss in dB>\n", simOpt, .dblptr=&(rfsimulator->chan_pathloss), .defdblval=0, TYPE_DOUBLE, 0 },\
|
||||||
{"forgetfact", "<channel forget factor ((0 to 1)>\n", simOpt, .dblptr=&(rfsimulator->chan_forgetfact),.defdblval=0, TYPE_DOUBLE, 0 },\
|
{"forgetfact", "<channel forget factor ((0 to 1)>\n", simOpt, .dblptr=&(rfsimulator->chan_forgetfact),.defdblval=0, TYPE_DOUBLE, 0 },\
|
||||||
{"offset", "<channel offset in samps>\n", simOpt, .iptr=&(rfsimulator->chan_offset), .defintval=0, TYPE_INT, 0 },\
|
{"offset", "<channel offset in samps>\n", simOpt, .u64ptr=&(rfsimulator->chan_offset), .defint64val=0, TYPE_UINT64, 0 },\
|
||||||
|
{"prop_delay", "<propagation delay in ms>\n", simOpt, .dblptr=&(rfsimulator->prop_delay_ms), .defdblval=0.0, TYPE_DOUBLE, 0 },\
|
||||||
{"wait_timeout", "<wait timeout if no UE connected>\n", simOpt, .iptr=&(rfsimulator->wait_timeout), .defintval=1, TYPE_INT, 0 },\
|
{"wait_timeout", "<wait timeout if no UE connected>\n", simOpt, .iptr=&(rfsimulator->wait_timeout), .defintval=1, TYPE_INT, 0 },\
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -138,6 +139,8 @@ static telnetshell_vardef_t rfsimu_vardef[] = {{"", 0, 0, NULL}};
|
|||||||
pthread_mutex_t Sockmutex;
|
pthread_mutex_t Sockmutex;
|
||||||
unsigned int nb_ue = 0;
|
unsigned int nb_ue = 0;
|
||||||
|
|
||||||
|
static uint64_t CirSize = minCirSize;
|
||||||
|
|
||||||
typedef c16_t sample_t; // 2*16 bits complex number
|
typedef c16_t sample_t; // 2*16 bits complex number
|
||||||
|
|
||||||
typedef struct buffer_s {
|
typedef struct buffer_s {
|
||||||
@@ -169,11 +172,12 @@ typedef struct {
|
|||||||
int channelmod;
|
int channelmod;
|
||||||
double chan_pathloss;
|
double chan_pathloss;
|
||||||
double chan_forgetfact;
|
double chan_forgetfact;
|
||||||
int chan_offset;
|
uint64_t chan_offset;
|
||||||
float noise_power_dB;
|
float noise_power_dB;
|
||||||
void *telnetcmd_qid;
|
void *telnetcmd_qid;
|
||||||
poll_telnetcmdq_func_t poll_telnetcmdq;
|
poll_telnetcmdq_func_t poll_telnetcmdq;
|
||||||
int wait_timeout;
|
int wait_timeout;
|
||||||
|
double prop_delay_ms;
|
||||||
} rfsimulator_state_t;
|
} rfsimulator_state_t;
|
||||||
|
|
||||||
static int allocCirBuf(rfsimulator_state_t *bridge, int sock)
|
static int allocCirBuf(rfsimulator_state_t *bridge, int sock)
|
||||||
@@ -403,7 +407,7 @@ static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt,
|
|||||||
0.0,
|
0.0,
|
||||||
CORR_LEVEL_LOW,
|
CORR_LEVEL_LOW,
|
||||||
t->chan_forgetfact, // forgetting_factor
|
t->chan_forgetfact, // forgetting_factor
|
||||||
t->chan_offset, // maybe used for TA
|
t->chan_offset, // propagation delay in samples
|
||||||
t->chan_pathloss,
|
t->chan_pathloss,
|
||||||
t->noise_power_dB); // path_loss in dB
|
t->noise_power_dB); // path_loss in dB
|
||||||
set_channeldesc_owner(newmodel, RFSIMU_MODULEID);
|
set_channeldesc_owner(newmodel, RFSIMU_MODULEID);
|
||||||
@@ -460,60 +464,6 @@ static void getset_currentchannels_type(char *buf, int debug, webdatadef_t *tdat
|
|||||||
// printf("\n");
|
// printf("\n");
|
||||||
//}
|
//}
|
||||||
|
|
||||||
static void rfsimu_offset_change_cirBuf(struct complex16 *circularBuf,
|
|
||||||
uint64_t firstSample,
|
|
||||||
uint32_t cirSize,
|
|
||||||
int old_offset,
|
|
||||||
int new_offset,
|
|
||||||
int nbTx)
|
|
||||||
{
|
|
||||||
//int start = max(new_offset, old_offset) + 10;
|
|
||||||
//int end = 10;
|
|
||||||
//printf("new_offset %d old_offset %d start %d end %d\n", new_offset, old_offset, start, end);
|
|
||||||
//printf("ringbuffer before:\n");
|
|
||||||
//print_cirBuf(circularBuf, firstSample, cirSize, start, end, nbTx);
|
|
||||||
|
|
||||||
int doffset = new_offset - old_offset;
|
|
||||||
if (doffset > 0) {
|
|
||||||
/* Moving away, creating a gap. We need to insert "zero" samples between
|
|
||||||
* the previous (end of the) slot and the new slot (at the ringbuffer
|
|
||||||
* index) to prevent that the receiving side detects things that are not
|
|
||||||
* in the channel (e.g., samples that have already been delivered). */
|
|
||||||
for (int i = new_offset; i > 0; --i) {
|
|
||||||
for (int txAnt = 0; txAnt < nbTx; txAnt++) {
|
|
||||||
const int newidx = ((firstSample - i) * nbTx + txAnt + cirSize) % cirSize;
|
|
||||||
if (i > doffset) {
|
|
||||||
// shift samples not read yet
|
|
||||||
const int oldidx = (newidx + doffset) % cirSize;
|
|
||||||
circularBuf[newidx] = circularBuf[oldidx];
|
|
||||||
} else {
|
|
||||||
// create zero samples between slots
|
|
||||||
const struct complex16 nullsample = {0, 0};
|
|
||||||
circularBuf[newidx] = nullsample;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Moving closer, creating overlap between samples. For simplicity, we
|
|
||||||
* simply drop `doffset` samples at the end of the previous slot
|
|
||||||
* (this is, in a sense, arbitrary). In a real channel, there would be
|
|
||||||
* some overlap between samples, e.g., for `doffset == 1` we could add
|
|
||||||
* two samples. I think that we cannot do that for multiple samples,
|
|
||||||
* though, and so we just drop some */
|
|
||||||
// drop the last -doffset samples of the previous slot
|
|
||||||
for (int i = old_offset; i > -doffset; --i) {
|
|
||||||
for (int txAnt = 0; txAnt < nbTx; txAnt++) {
|
|
||||||
const int oldidx = ((firstSample - i) * nbTx + txAnt + cirSize) % cirSize;
|
|
||||||
const int newidx = (oldidx - doffset) % cirSize;
|
|
||||||
circularBuf[newidx] = circularBuf[oldidx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//printf("ringbuffer after:\n");
|
|
||||||
//print_cirBuf(circularBuf, firstSample, cirSize, start, end, nbTx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg)
|
static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg)
|
||||||
{
|
{
|
||||||
if (debug)
|
if (debug)
|
||||||
@@ -531,10 +481,13 @@ static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt
|
|||||||
const double sample_rate = t->sample_rate;
|
const double sample_rate = t->sample_rate;
|
||||||
const double c = 299792458; /* 3e8 */
|
const double c = 299792458; /* 3e8 */
|
||||||
|
|
||||||
const int new_offset = (double) distance * sample_rate / c;
|
const uint64_t new_offset = (double) distance * sample_rate / c;
|
||||||
const double new_distance = (double) new_offset * c / sample_rate;
|
const double new_distance = (double) new_offset * c / sample_rate;
|
||||||
|
const double new_delay_ms = new_offset * 1000.0 / sample_rate;
|
||||||
|
|
||||||
prnt("\n%s: new_offset %d new (exact) distance %.3f m\n", __func__, new_offset, new_distance);
|
prnt("\n%s: new_offset %lu, new (exact) distance %.3f m, new delay %f ms\n", __func__, new_offset, new_distance, new_delay_ms);
|
||||||
|
t->prop_delay_ms = new_delay_ms;
|
||||||
|
t->chan_offset = new_offset;
|
||||||
|
|
||||||
/* Set distance in rfsim and channel model, update channel and ringbuffer */
|
/* Set distance in rfsim and channel model, update channel and ringbuffer */
|
||||||
for (int i = 0; i < MAX_FD_RFSIMU; i++) {
|
for (int i = 0; i < MAX_FD_RFSIMU; i++) {
|
||||||
@@ -546,12 +499,7 @@ static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt
|
|||||||
}
|
}
|
||||||
|
|
||||||
channel_desc_t *cd = b->channel_model;
|
channel_desc_t *cd = b->channel_model;
|
||||||
const int old_offset = cd->channel_offset;
|
|
||||||
cd->channel_offset = new_offset;
|
cd->channel_offset = new_offset;
|
||||||
|
|
||||||
const int nbTx = cd->nb_tx;
|
|
||||||
prnt(" %s: Modifying model %s...\n", __func__, modelname);
|
|
||||||
rfsimu_offset_change_cirBuf(b->circularBuf, t->nextRxTstamp, CirSize, old_offset, new_offset, nbTx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(modelname);
|
free(modelname);
|
||||||
@@ -574,10 +522,11 @@ static int rfsimu_getdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
channel_desc_t *cd = b->channel_model;
|
channel_desc_t *cd = b->channel_model;
|
||||||
const int offset = cd->channel_offset;
|
const uint64_t offset = cd->channel_offset;
|
||||||
const double distance = (double) offset * c / sample_rate;
|
const double distance = (double) offset * c / sample_rate;
|
||||||
prnt("%s: \%s offset %d distance %.3f m\n", __func__, cd->model_name, offset, distance);
|
prnt("%s: %s offset %lu distance %.3f m\n", __func__, cd->model_name, offset, distance);
|
||||||
}
|
}
|
||||||
|
prnt("%s: <default> offset %lu delay %f ms\n", __func__, t->chan_offset, t->prop_delay_ms);
|
||||||
|
|
||||||
return CMDSTATUS_FOUND;
|
return CMDSTATUS_FOUND;
|
||||||
}
|
}
|
||||||
@@ -726,9 +675,16 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp
|
|||||||
if ( t->lastWroteTS != 0 && fabs((double)t->lastWroteTS-timestamp) > (double)CirSize)
|
if ( t->lastWroteTS != 0 && fabs((double)t->lastWroteTS-timestamp) > (double)CirSize)
|
||||||
LOG_W(HW, "Discontinuous TX gap too large Tx:%lu, %lu\n", t->lastWroteTS, timestamp);
|
LOG_W(HW, "Discontinuous TX gap too large Tx:%lu, %lu\n", t->lastWroteTS, timestamp);
|
||||||
|
|
||||||
if (t->lastWroteTS > timestamp+nsamps)
|
if (t->lastWroteTS > timestamp)
|
||||||
LOG_W(HW, "Not supported to send Tx out of order %lu, %lu\n", t->lastWroteTS, timestamp);
|
LOG_W(HW, "Not supported to send Tx out of order %lu, %lu\n", t->lastWroteTS, timestamp);
|
||||||
|
|
||||||
|
if ((flags != TX_BURST_START) && (flags != TX_BURST_START_AND_END) && (t->lastWroteTS < timestamp))
|
||||||
|
LOG_W(HW,
|
||||||
|
"Gap in writing to USRP: last written %lu, now %lu, gap %lu\n",
|
||||||
|
t->lastWroteTS,
|
||||||
|
timestamp,
|
||||||
|
timestamp - t->lastWroteTS);
|
||||||
|
|
||||||
t->lastWroteTS=timestamp+nsamps;
|
t->lastWroteTS=timestamp+nsamps;
|
||||||
|
|
||||||
if (!alreadyLocked)
|
if (!alreadyLocked)
|
||||||
@@ -983,16 +939,16 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest
|
|||||||
}
|
}
|
||||||
else { // no channel modeling
|
else { // no channel modeling
|
||||||
int nbAnt_tx = ptr->th.nbAnt; // number of Tx antennas
|
int nbAnt_tx = ptr->th.nbAnt; // number of Tx antennas
|
||||||
|
int firstIndex = (CirSize + t->nextRxTstamp - t->chan_offset) % CirSize;
|
||||||
|
sample_t *out = (sample_t *)samplesVoid[a];
|
||||||
if ((nbAnt_tx == 1) && ((nb_ue == 1) || (t->role == SIMU_ROLE_CLIENT))) { // optimized for 1 Tx and 1 UE
|
if ((nbAnt_tx == 1) && ((nb_ue == 1) || (t->role == SIMU_ROLE_CLIENT))) { // optimized for 1 Tx and 1 UE
|
||||||
sample_t *out = (sample_t *)samplesVoid[a];
|
|
||||||
int firstIndex = t->nextRxTstamp % CirSize;
|
|
||||||
sample_t *firstSample = (sample_t *)&(ptr->circularBuf[firstIndex]);
|
sample_t *firstSample = (sample_t *)&(ptr->circularBuf[firstIndex]);
|
||||||
if (firstIndex + nsamps > CirSize) {
|
if (firstIndex + nsamps > CirSize) {
|
||||||
int tailSz = CirSize - firstIndex;
|
int tailSz = CirSize - firstIndex;
|
||||||
memcpy(out, firstSample, sampleToByte(tailSz, nbAnt_tx));
|
memcpy(out, firstSample, sampleToByte(tailSz, 1));
|
||||||
memcpy(out + tailSz, &ptr->circularBuf[0], sampleToByte(nsamps - tailSz, nbAnt_tx));
|
memcpy(out + tailSz, &ptr->circularBuf[0], sampleToByte(nsamps - tailSz, 1));
|
||||||
} else {
|
} else {
|
||||||
memcpy(out, firstSample, nsamps * 4);
|
memcpy(out, firstSample, sampleToByte(nsamps, 1));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// SIMD (with simde) optimization might be added here later
|
// SIMD (with simde) optimization might be added here later
|
||||||
@@ -1001,13 +957,11 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest
|
|||||||
{0.1, 0.2, 1.0, 0.2}, // rx 2
|
{0.1, 0.2, 1.0, 0.2}, // rx 2
|
||||||
{0.05, 0.1, 0.2, 1.0}}; // rx 3
|
{0.05, 0.1, 0.2, 1.0}}; // rx 3
|
||||||
|
|
||||||
sample_t *out = (sample_t *)samplesVoid[a];
|
|
||||||
|
|
||||||
LOG_D(HW, "nbAnt_tx %d\n", nbAnt_tx);
|
LOG_D(HW, "nbAnt_tx %d\n", nbAnt_tx);
|
||||||
for (int i = 0; i < nsamps; i++) { // loop over nsamps
|
for (int i = 0; i < nsamps; i++) { // loop over nsamps
|
||||||
for (int a_tx = 0; a_tx < nbAnt_tx; a_tx++) { // sum up signals from nbAnt_tx antennas
|
for (int a_tx = 0; a_tx < nbAnt_tx; a_tx++) { // sum up signals from nbAnt_tx antennas
|
||||||
out[i].r += (short)(ptr->circularBuf[((t->nextRxTstamp + i) * nbAnt_tx + a_tx) % CirSize].r * H_awgn_mimo[a][a_tx]);
|
out[i].r += (short)(ptr->circularBuf[((firstIndex + i) * nbAnt_tx + a_tx) % CirSize].r * H_awgn_mimo[a][a_tx]);
|
||||||
out[i].i += (short)(ptr->circularBuf[((t->nextRxTstamp + i) * nbAnt_tx + a_tx) % CirSize].i * H_awgn_mimo[a][a_tx]);
|
out[i].i += (short)(ptr->circularBuf[((firstIndex + i) * nbAnt_tx + a_tx) % CirSize].i * H_awgn_mimo[a][a_tx]);
|
||||||
} // end for a_tx
|
} // end for a_tx
|
||||||
} // end for i (number of samps)
|
} // end for i (number of samps)
|
||||||
} // end of 1 tx antenna optimization
|
} // end of 1 tx antenna optimization
|
||||||
@@ -1066,6 +1020,16 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
|||||||
rfsimulator->tx_bw=openair0_cfg->tx_bw;
|
rfsimulator->tx_bw=openair0_cfg->tx_bw;
|
||||||
rfsimulator_readconfig(rfsimulator);
|
rfsimulator_readconfig(rfsimulator);
|
||||||
LOG_W(HW, "sample_rate %f\n", rfsimulator->sample_rate);
|
LOG_W(HW, "sample_rate %f\n", rfsimulator->sample_rate);
|
||||||
|
if (rfsimulator->prop_delay_ms > 0.0)
|
||||||
|
rfsimulator->chan_offset = rfsimulator->sample_rate * rfsimulator->prop_delay_ms / 1000;
|
||||||
|
if (rfsimulator->chan_offset != 0) {
|
||||||
|
if (CirSize < minCirSize + rfsimulator->chan_offset) {
|
||||||
|
CirSize = minCirSize + rfsimulator->chan_offset;
|
||||||
|
LOG_I(HW, "CirSize = %lu\n", CirSize);
|
||||||
|
}
|
||||||
|
rfsimulator->prop_delay_ms = rfsimulator->chan_offset * 1000 / rfsimulator->sample_rate;
|
||||||
|
LOG_I(HW, "propagation delay %f ms, %lu samples\n", rfsimulator->prop_delay_ms, rfsimulator->chan_offset);
|
||||||
|
}
|
||||||
pthread_mutex_init(&Sockmutex, NULL);
|
pthread_mutex_init(&Sockmutex, NULL);
|
||||||
LOG_I(HW,
|
LOG_I(HW,
|
||||||
"Running as %s\n",
|
"Running as %s\n",
|
||||||
|
|||||||
Reference in New Issue
Block a user