Merge remote-tracking branch 'origin/rfsim_add_prop_delay' into integration_2024_w21c
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);
|
||||
|
||||
if (((cfgoptions->paramflags & PARAMFLAG_MANDATORY) == 0)) {
|
||||
*(cfgoptions->u64ptr) = cfgoptions->defuintval;
|
||||
*(cfgoptions->u64ptr) = cfgoptions->defint64val;
|
||||
status=1;
|
||||
printf_params(cfg,
|
||||
"[CONFIG] %s.%s set to default value %llu\n",
|
||||
|
||||
@@ -55,12 +55,12 @@ void __attribute__ ((no_sanitize_address)) multipath_channel(channel_desc_t *des
|
||||
tx128_re, tx128_im, ch128_x, ch128_y, pathloss128;
|
||||
|
||||
double path_loss = pow(10,desc->path_loss_dB/20);
|
||||
int dd = abs(desc->channel_offset);
|
||||
uint64_t dd = desc->channel_offset;
|
||||
|
||||
pathloss128 = simde_mm_set1_pd(path_loss);
|
||||
|
||||
#ifdef DEBUG_CH
|
||||
printf("[CHANNEL] keep = %d : path_loss = %g (%f), nb_rx %d, nb_tx %d, dd %d, len %d \n",keep_channel,path_loss,desc->path_loss_dB,desc->nb_rx,desc->nb_tx,dd,desc->channel_length);
|
||||
printf("[CHANNEL] keep = %d : path_loss = %g (%f), nb_rx %d, nb_tx %d, dd %lu, len %d \n",keep_channel,path_loss,desc->path_loss_dB,desc->nb_rx,desc->nb_tx,dd,desc->channel_length);
|
||||
#endif
|
||||
|
||||
if (keep_channel) {
|
||||
@@ -184,11 +184,10 @@ void __attribute__ ((no_sanitize_address)) multipath_channel(channel_desc_t *des
|
||||
{
|
||||
|
||||
double path_loss = pow(10,desc->path_loss_dB/20);
|
||||
int dd;
|
||||
dd = abs(desc->channel_offset);
|
||||
uint64_t dd = desc->channel_offset;
|
||||
|
||||
#ifdef DEBUG_CH
|
||||
printf("[CHANNEL] keep = %d : path_loss = %g (%f), nb_rx %d, nb_tx %d, dd %d, len %d \n",
|
||||
printf("[CHANNEL] keep = %d : path_loss = %g (%f), nb_rx %d, nb_tx %d, dd %lu, len %d \n",
|
||||
keep_channel, path_loss, desc->path_loss_dB, desc->nb_rx, desc->nb_tx, dd, desc->channel_length);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
void tv_channel(channel_desc_t *desc,double complex ***H,uint32_t length);
|
||||
double frand_a_b(double a, double b);
|
||||
void tv_conv(double complex **h, double complex *x, double complex *y, uint32_t nb_samples, uint8_t nb_taps, int delay);
|
||||
void tv_conv(double complex **h, double complex *x, double complex *y, uint32_t nb_samples, uint8_t nb_taps, uint64_t delay);
|
||||
|
||||
void multipath_tv_channel(channel_desc_t *desc,
|
||||
double **tx_sig_re,
|
||||
@@ -42,10 +42,10 @@ void multipath_tv_channel(channel_desc_t *desc,
|
||||
|
||||
double complex **tx,**rx,***H_t;
|
||||
double path_loss = pow(10,desc->path_loss_dB/20);
|
||||
int i,j,dd;
|
||||
dd = abs(desc->channel_offset);
|
||||
int i,j;
|
||||
uint64_t dd = desc->channel_offset;
|
||||
#ifdef DEBUG_CH
|
||||
printf("[TV CHANNEL] keep = %d : path_loss = %g (%f), nb_rx %d, nb_tx %d, dd %d, len %d max_doppler %g\n",keep_channel,path_loss,desc->path_loss_dB,desc->nb_rx,desc->nb_tx,dd,desc->channel_length,
|
||||
printf("[TV CHANNEL] keep = %d : path_loss = %g (%f), nb_rx %d, nb_tx %d, dd %lu, len %d max_doppler %g\n",keep_channel,path_loss,desc->path_loss_dB,desc->nb_rx,desc->nb_tx,dd,desc->channel_length,
|
||||
desc->max_Doppler);
|
||||
#endif
|
||||
tx = (double complex **)malloc(desc->nb_tx*sizeof(double complex *));
|
||||
@@ -190,7 +190,7 @@ void tv_channel(channel_desc_t *desc,double complex ***H,uint32_t length){
|
||||
}
|
||||
|
||||
// time varying convolution
|
||||
void tv_conv(double complex **h, double complex *x, double complex *y, uint32_t nb_samples, uint8_t nb_taps, int dd)
|
||||
void tv_conv(double complex **h, double complex *x, double complex *y, uint32_t nb_samples, uint8_t nb_taps, uint64_t dd)
|
||||
{
|
||||
for(int i = 0; i < ((int)nb_samples-dd); i++) {
|
||||
for(int j = 0; j < nb_taps; j++) {
|
||||
|
||||
@@ -76,7 +76,6 @@ static unsigned int max_chan;
|
||||
static channel_desc_t **defined_channels;
|
||||
static char *modellist_name;
|
||||
|
||||
|
||||
void fill_channel_desc(channel_desc_t *chan_desc,
|
||||
uint8_t nb_tx,
|
||||
uint8_t nb_rx,
|
||||
@@ -92,9 +91,10 @@ void fill_channel_desc(channel_desc_t *chan_desc,
|
||||
double aoa,
|
||||
double forgetting_factor,
|
||||
double max_Doppler,
|
||||
int32_t channel_offset,
|
||||
uint64_t channel_offset,
|
||||
double path_loss_dB,
|
||||
uint8_t random_aoa) {
|
||||
uint8_t random_aoa)
|
||||
{
|
||||
uint16_t i,j;
|
||||
double delta_tau;
|
||||
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,
|
||||
const corr_level_t corr_level,
|
||||
double forgetting_factor,
|
||||
int32_t channel_offset,
|
||||
uint64_t channel_offset,
|
||||
double path_loss_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("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"));
|
||||
prnt("max Doppler: %lf path loss: %lf noise: %lf rchannel offset: %i forget factor; %lf\n",
|
||||
cd->max_Doppler, cd->path_loss_dB, cd->noise_power_dB, cd->channel_offset, cd->forgetting_factor);
|
||||
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);
|
||||
prnt("Initial phase: %lf nb_path: %i \n",
|
||||
cd->ip, cd->nb_paths);
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ typedef struct {
|
||||
///path loss including shadow fading in dB
|
||||
double path_loss_dB;
|
||||
///additional delay of channel in samples.
|
||||
int32_t channel_offset;
|
||||
uint64_t channel_offset;
|
||||
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
|
||||
double forgetting_factor;
|
||||
@@ -307,7 +307,6 @@ typedef struct {
|
||||
double ru_amp[NUMBER_OF_RU_MAX];
|
||||
} sim_t;
|
||||
|
||||
|
||||
channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
|
||||
uint8_t nb_rx,
|
||||
SCM_t channel_model,
|
||||
@@ -318,7 +317,7 @@ channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
|
||||
double maxDoppler,
|
||||
const corr_level_t corr_level,
|
||||
double forgetting_factor,
|
||||
int32_t channel_offset,
|
||||
uint64_t channel_offset,
|
||||
double path_loss_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.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 saviq` | store IQs to a file for future replay | 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 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.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 |
|
||||
|
||||
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.
|
||||
|
||||
## 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
|
||||
|
||||
There are issues in power control: txgain/rxgain setting is not supported.
|
||||
|
||||
@@ -68,7 +68,7 @@ void rxAddInput( const c16_t *input_sig,
|
||||
// Energy in one sample to calibrate input noise
|
||||
// the normalized OAI value seems to be 256 as average amplitude (numerical amplification = 1)
|
||||
const double noise_per_sample = pow(10,channelDesc->noise_power_dB/10.0) * 256;
|
||||
const int dd = abs(channelDesc->channel_offset);
|
||||
const uint64_t dd = channelDesc->channel_offset;
|
||||
const int nbTx=channelDesc->nb_tx;
|
||||
|
||||
for (int i=0; i<nbSamples; i++) {
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
// 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
|
||||
// #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 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 },\
|
||||
{"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 },\
|
||||
{"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 },\
|
||||
};
|
||||
|
||||
@@ -138,6 +139,8 @@ static telnetshell_vardef_t rfsimu_vardef[] = {{"", 0, 0, NULL}};
|
||||
pthread_mutex_t Sockmutex;
|
||||
unsigned int nb_ue = 0;
|
||||
|
||||
static uint64_t CirSize = minCirSize;
|
||||
|
||||
typedef c16_t sample_t; // 2*16 bits complex number
|
||||
|
||||
typedef struct buffer_s {
|
||||
@@ -169,11 +172,12 @@ typedef struct {
|
||||
int channelmod;
|
||||
double chan_pathloss;
|
||||
double chan_forgetfact;
|
||||
int chan_offset;
|
||||
uint64_t chan_offset;
|
||||
float noise_power_dB;
|
||||
void *telnetcmd_qid;
|
||||
poll_telnetcmdq_func_t poll_telnetcmdq;
|
||||
int wait_timeout;
|
||||
double prop_delay_ms;
|
||||
} rfsimulator_state_t;
|
||||
|
||||
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,
|
||||
CORR_LEVEL_LOW,
|
||||
t->chan_forgetfact, // forgetting_factor
|
||||
t->chan_offset, // maybe used for TA
|
||||
t->chan_offset, // propagation delay in samples
|
||||
t->chan_pathloss,
|
||||
t->noise_power_dB); // path_loss in dB
|
||||
set_channeldesc_owner(newmodel, RFSIMU_MODULEID);
|
||||
@@ -460,60 +464,6 @@ static void getset_currentchannels_type(char *buf, int debug, webdatadef_t *tdat
|
||||
// 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)
|
||||
{
|
||||
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 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_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 */
|
||||
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;
|
||||
const int old_offset = cd->channel_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);
|
||||
@@ -574,10 +522,11 @@ static int rfsimu_getdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt
|
||||
continue;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
@@ -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)
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
if (!alreadyLocked)
|
||||
@@ -983,16 +939,16 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest
|
||||
}
|
||||
else { // no channel modeling
|
||||
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
|
||||
sample_t *out = (sample_t *)samplesVoid[a];
|
||||
int firstIndex = t->nextRxTstamp % CirSize;
|
||||
sample_t *firstSample = (sample_t *)&(ptr->circularBuf[firstIndex]);
|
||||
if (firstIndex + nsamps > CirSize) {
|
||||
int tailSz = CirSize - firstIndex;
|
||||
memcpy(out, firstSample, sampleToByte(tailSz, nbAnt_tx));
|
||||
memcpy(out + tailSz, &ptr->circularBuf[0], sampleToByte(nsamps - tailSz, nbAnt_tx));
|
||||
memcpy(out, firstSample, sampleToByte(tailSz, 1));
|
||||
memcpy(out + tailSz, &ptr->circularBuf[0], sampleToByte(nsamps - tailSz, 1));
|
||||
} else {
|
||||
memcpy(out, firstSample, nsamps * 4);
|
||||
memcpy(out, firstSample, sampleToByte(nsamps, 1));
|
||||
}
|
||||
} else {
|
||||
// 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.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);
|
||||
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
|
||||
out[i].r += (short)(ptr->circularBuf[((t->nextRxTstamp + 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].r += (short)(ptr->circularBuf[((firstIndex + i) * nbAnt_tx + a_tx) % CirSize].r * 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 i (number of samps)
|
||||
} // 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_readconfig(rfsimulator);
|
||||
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);
|
||||
LOG_I(HW,
|
||||
"Running as %s\n",
|
||||
|
||||
Reference in New Issue
Block a user