SRSUE: Created delay channel emulator and added fading to the UE

This commit is contained in:
Xavier Arteaga 2019-05-27 18:21:55 +02:00 committed by Andre Puschmann
parent 709e769d0d
commit 9ab2b2de81
13 changed files with 451 additions and 28 deletions

View File

@ -35,6 +35,7 @@
#include "srslte/common/common.h"
#include "srslte/common/interfaces_common.h"
#include "srslte/common/security.h"
#include "srslte/phy/channel/channel.h"
#include "srslte/phy/rf/rf.h"
#include "srslte/upper/rlc_interface.h"
@ -758,6 +759,7 @@ typedef struct {
uint32_t intra_freq_meas_len_ms;
uint32_t intra_freq_meas_period_ms;
bool pregenerate_signals;
srslte::channel::args_t dl_channel_args;
} phy_args_t;

View File

@ -0,0 +1,66 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_CHANNEL_H
#define SRSLTE_CHANNEL_H
#include "delay.h"
#include "fading.h"
#include <srslte/config.h>
#include <srslte/srslte.h>
#include <string>
namespace srslte {
class channel
{
public:
typedef struct {
// General
bool enable = false;
// Fading options
std::string fading_model = "";
// Delay options
float delay_min_us = 0;
float delay_max_us = 0;
uint32_t delay_period_s = 0;
} args_t;
channel(const args_t& channel_args, uint32_t _nof_ports);
~channel();
void set_srate(uint32_t srate);
void run(cf_t* in[SRSLTE_MAX_PORTS], cf_t* out[SRSLTE_MAX_PORTS], uint32_t len, const srslte_timestamp_t& t);
private:
srslte_channel_fading_t* fading[SRSLTE_MAX_PORTS];
srslte_channel_delay_t* delay[SRSLTE_MAX_PORTS];
cf_t* buffer_in = nullptr;
cf_t* buffer_out = nullptr;
uint32_t nof_ports = 0;
uint32_t current_srate = 0;
args_t args;
};
} // namespace srslte
#endif // SRSLTE_CHANNEL_H

View File

@ -0,0 +1,58 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_DELAY_H
#define SRSLTE_DELAY_H
#include <srslte/config.h>
#include <srslte/phy/common/timestamp.h>
#include <srslte/phy/utils/ringbuffer.h>
typedef struct {
float delay_min_us;
float delay_max_us;
uint32_t period_s;
uint32_t srate_max_hz;
uint32_t srate_hz;
srslte_ringbuffer_t rb;
cf_t* zero_buffer;
} srslte_channel_delay_t;
#ifdef __cplusplus
extern "C" {
#endif
SRSLTE_API int srslte_channel_delay_init(
srslte_channel_delay_t* q, float delay_min_ns, float delay_max_ns, uint32_t period_s, uint32_t srate_max_hz);
SRSLTE_API void srslte_channel_delay_update_srate(srslte_channel_delay_t* q, uint32_t srate_hz);
SRSLTE_API void srslte_channel_delay_free(srslte_channel_delay_t* q);
SRSLTE_API void srslte_channel_delay_execute(
srslte_channel_delay_t* q, const cf_t* in, cf_t* out, uint32_t len, const srslte_timestamp_t* ts);
#ifdef __cplusplus
}
#endif
#endif // SRSLTE_DELAY_H

View File

@ -58,6 +58,10 @@ typedef struct {
cf_t* state; // Length fft_size/2
} srslte_channel_fading_t;
#ifdef __cplusplus
extern "C" {
#endif
SRSLTE_API int srslte_channel_fading_init(srslte_channel_fading_t* q, double srate, const char* model, uint32_t seed);
SRSLTE_API void srslte_channel_fading_free(srslte_channel_fading_t* q);
@ -65,4 +69,8 @@ SRSLTE_API void srslte_channel_fading_free(srslte_channel_fading_t* q);
SRSLTE_API double srslte_channel_fading_execute(
srslte_channel_fading_t* q, const cf_t* in, cf_t* out, uint32_t nof_samples, double init_time);
#ifdef __cplusplus
}
#endif
#endif // SRSLTE_FADING_H

View File

@ -42,24 +42,21 @@ typedef struct SRSLTE_API{
double frac_secs;
}srslte_timestamp_t;
SRSLTE_API int srslte_timestamp_init(srslte_timestamp_t *t,
time_t full_secs,
double frac_secs);
#ifdef __cplusplus
extern "C" {
#endif
SRSLTE_API int srslte_timestamp_init(srslte_timestamp_t* t, time_t full_secs, double frac_secs);
SRSLTE_API void srslte_timestamp_init_uint64(srslte_timestamp_t* ts_time, uint64_t ts_count, double base_srate);
SRSLTE_API int srslte_timestamp_copy(srslte_timestamp_t *dest,
srslte_timestamp_t *src);
SRSLTE_API int srslte_timestamp_copy(srslte_timestamp_t* dest, srslte_timestamp_t* src);
SRSLTE_API int srslte_timestamp_compare(srslte_timestamp_t* a, srslte_timestamp_t* b);
SRSLTE_API int srslte_timestamp_add(srslte_timestamp_t *t,
time_t full_secs,
double frac_secs);
SRSLTE_API int srslte_timestamp_add(srslte_timestamp_t* t, time_t full_secs, double frac_secs);
SRSLTE_API int srslte_timestamp_sub(srslte_timestamp_t *t,
time_t full_secs,
double frac_secs);
SRSLTE_API int srslte_timestamp_sub(srslte_timestamp_t* t, time_t full_secs, double frac_secs);
SRSLTE_API double srslte_timestamp_real(srslte_timestamp_t *t);
@ -69,4 +66,8 @@ SRSLTE_API uint32_t srslte_timestamp_uint32(srslte_timestamp_t *t);
SRSLTE_API uint64_t srslte_timestamp_uint64(const srslte_timestamp_t* t, double srate);
#ifdef __cplusplus
}
#endif
#endif // SRSLTE_TIMESTAMP_H

View File

@ -30,38 +30,40 @@
typedef struct {
uint8_t *buffer;
bool active;
int capacity;
int count;
int wpm;
int rpm;
pthread_mutex_t mutex;
pthread_cond_t cvar;
} srslte_ringbuffer_t;
int capacity;
int count;
int wpm;
int rpm;
pthread_mutex_t mutex;
pthread_cond_t cvar;
} srslte_ringbuffer_t;
#ifdef __cplusplus
extern "C" {
#endif
SRSLTE_API int srslte_ringbuffer_init(srslte_ringbuffer_t *q,
int capacity);
SRSLTE_API int srslte_ringbuffer_init(srslte_ringbuffer_t* q, int capacity);
SRSLTE_API void srslte_ringbuffer_free(srslte_ringbuffer_t *q);
SRSLTE_API void srslte_ringbuffer_reset(srslte_ringbuffer_t *q);
SRSLTE_API int srslte_ringbuffer_status(srslte_ringbuffer_t *q);
SRSLTE_API int srslte_ringbuffer_status(srslte_ringbuffer_t* q);
SRSLTE_API int srslte_ringbuffer_space(srslte_ringbuffer_t *q);
SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t *q,
void *ptr,
int nof_bytes);
SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t* q, void* ptr, int nof_bytes);
SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t *q,
void *ptr,
int nof_bytes);
SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t* q, void* ptr, int nof_bytes);
SRSLTE_API int srslte_ringbuffer_read_timed(srslte_ringbuffer_t* q, void* p, int nof_bytes, uint32_t timeout_ms);
SRSLTE_API void srslte_ringbuffer_stop(srslte_ringbuffer_t *q);
#ifdef __cplusplus
}
#endif
#endif // SRSLTE_RINGBUFFER_H

View File

@ -18,7 +18,7 @@
# and at http://www.gnu.org/licenses/.
#
file(GLOB SOURCES "*.c")
file(GLOB SOURCES "*.c" "*.cc")
add_library(srslte_channel OBJECT ${SOURCES})
add_subdirectory(test)

View File

@ -0,0 +1,130 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <cstdlib>
#include <srslte/phy/channel/channel.h>
#include <srslte/srslte.h>
using namespace srslte;
channel::channel(const channel::args_t& channel_args, uint32_t _nof_ports)
{
int ret = SRSLTE_SUCCESS;
uint32_t srate_max = (uint32_t)srslte_symbol_sz(SRSLTE_MAX_PRB) * 15000;
uint32_t buffer_size = (uint32_t)SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB) * 5; // be safe, 5 Subframes
// Copy args
args = channel_args;
// Allocate internal buffers
buffer_in = (cf_t*)srslte_vec_malloc(sizeof(cf_t) * buffer_size);
buffer_out = (cf_t*)srslte_vec_malloc(sizeof(cf_t) * buffer_size);
if (!buffer_out || !buffer_in) {
ret = SRSLTE_ERROR;
}
nof_ports = _nof_ports;
for (uint32_t i = 0; i < nof_ports; i++) {
// Create fading channel
if (!channel_args.fading_model.empty() && channel_args.fading_model != "none" && ret == SRSLTE_SUCCESS) {
fading[i] = (srslte_channel_fading_t*)calloc(sizeof(srslte_channel_fading_t), 1);
ret = srslte_channel_fading_init(fading[i], srate_max, channel_args.fading_model.c_str(), 0x1234 * i);
} else {
fading[i] = nullptr;
}
// Create delay
if (channel_args.delay_period_s && ret == SRSLTE_SUCCESS) {
delay[i] = (srslte_channel_delay_t*)calloc(sizeof(srslte_channel_delay_t), 1);
ret = srslte_channel_delay_init(
delay[i], channel_args.delay_min_us, channel_args.delay_max_us, channel_args.delay_period_s, srate_max);
} else {
delay[i] = nullptr;
}
}
if (ret != SRSLTE_SUCCESS) {
fprintf(stderr, "Error: Creating channel\n\n");
}
}
channel::~channel()
{
if (buffer_in) {
free(buffer_in);
}
if (buffer_out) {
free(buffer_out);
}
for (uint32_t i = 0; i < nof_ports; i++) {
if (fading[i]) {
srslte_channel_fading_free(fading[i]);
free(fading[i]);
}
if (delay[i]) {
srslte_channel_delay_free(delay[i]);
free(delay[i]);
}
}
}
void channel::run(cf_t* in[SRSLTE_MAX_PORTS], cf_t* out[SRSLTE_MAX_PORTS], uint32_t len, const srslte_timestamp_t& t)
{
for (uint32_t i = 0; i < nof_ports; i++) {
// Copy input buffer
memcpy(buffer_in, in[i], sizeof(cf_t) * len);
if (fading[i]) {
srslte_channel_fading_execute(fading[i], buffer_in, buffer_out, len, t.full_secs + t.frac_secs);
memcpy(buffer_in, buffer_out, sizeof(cf_t) * len);
}
if (delay[i]) {
srslte_channel_delay_execute(delay[i], buffer_in, buffer_out, len, &t);
memcpy(buffer_in, buffer_out, sizeof(cf_t) * len);
}
// Copy output buffer
memcpy(out[i], buffer_out, sizeof(cf_t) * len);
}
}
void channel::set_srate(uint32_t srate)
{
if (current_srate != srate) {
for (uint32_t i = 0; i < nof_ports; i++) {
if (fading[i]) {
srslte_channel_fading_free(fading[i]);
srslte_channel_fading_init(fading[i], srate, args.fading_model.c_str(), 0x1234 * i);
}
if (delay[i]) {
srslte_channel_delay_update_srate(delay[i], srate);
}
current_srate = srate;
}
}
}

112
lib/src/phy/channel/delay.c Normal file
View File

@ -0,0 +1,112 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <math.h>
#include <srslte/phy/channel/delay.h>
#include <srslte/srslte.h>
static inline double caulculate_delay_us(srslte_channel_delay_t* q, const srslte_timestamp_t* ts)
{
uint32_t mod_secs = (uint32_t)(ts->full_secs % q->period_s);
double arg = 2.0 * M_PI * ((double)mod_secs + ts->frac_secs) / (double)q->period_s;
double delay_us = q->delay_min_us + (q->delay_max_us - q->delay_min_us) * (1.0 + sin(arg)) / 2.0;
return delay_us;
}
static inline uint32_t caulculate_delay_nsamples(srslte_channel_delay_t* q, double delay_us)
{
return (uint32_t)round(delay_us * (double)q->srate_hz / 1e6);
}
static inline uint32_t ringbuffer_available_nsamples(srslte_channel_delay_t* q)
{
return srslte_ringbuffer_status(&q->rb) / sizeof(cf_t);
}
int srslte_channel_delay_init(
srslte_channel_delay_t* q, float delay_min_us, float delay_max_us, uint32_t period_s, uint32_t srate_max_hz)
{
// Calculate buffer size
uint32_t buff_size = (uint32_t)ceilf(delay_max_us * (float)srate_max_hz);
// Create ring buffer
int ret = srslte_ringbuffer_init(&q->rb, sizeof(cf_t) * buff_size);
// Create zero buffer
q->zero_buffer = srslte_vec_malloc(sizeof(cf_t) * buff_size);
if (!q->zero_buffer) {
ret = SRSLTE_ERROR;
}
// Load initial parameters
q->delay_min_us = delay_min_us;
q->delay_max_us = delay_max_us;
q->srate_max_hz = srate_max_hz;
q->srate_hz = srate_max_hz;
q->period_s = period_s;
return ret;
}
void srslte_channel_delay_update_srate(srslte_channel_delay_t* q, uint32_t srate_hz)
{
srslte_ringbuffer_reset(&q->rb);
q->srate_hz = srate_hz;
}
void srslte_channel_delay_free(srslte_channel_delay_t* q)
{
srslte_ringbuffer_free(&q->rb);
if (q->zero_buffer) {
free(q->zero_buffer);
}
}
void srslte_channel_delay_execute(
srslte_channel_delay_t* q, const cf_t* in, cf_t* out, uint32_t len, const srslte_timestamp_t* ts)
{
double delay_us = caulculate_delay_us(q, ts);
uint32_t delay_nsamples = caulculate_delay_nsamples(q, delay_us);
uint32_t available_nsamples = ringbuffer_available_nsamples(q);
uint32_t read_nsamples = SRSLTE_MIN(delay_nsamples, len);
uint32_t copy_nsamples = (len > read_nsamples) ? (len - read_nsamples) : 0;
if (available_nsamples < delay_nsamples) {
uint32_t nzeros = delay_nsamples - available_nsamples;
bzero(q->zero_buffer, sizeof(cf_t) * nzeros);
srslte_ringbuffer_write(&q->rb, q->zero_buffer, sizeof(cf_t) * nzeros);
} else if (available_nsamples > delay_nsamples) {
srslte_ringbuffer_read(&q->rb, q->zero_buffer, sizeof(cf_t) * (available_nsamples - delay_nsamples));
}
// Read buffered samples
srslte_ringbuffer_read(&q->rb, out, sizeof(cf_t) * read_nsamples);
// Read other samples
if (copy_nsamples) {
memcpy(&out[read_nsamples], in, sizeof(cf_t) * copy_nsamples);
}
// Write new sampels
srslte_ringbuffer_write(&q->rb, (void*)&in[copy_nsamples], sizeof(cf_t) * read_nsamples);
}

View File

@ -24,6 +24,7 @@
#include <map>
#include <pthread.h>
#include <srslte/phy/channel/channel.h>
#include "async_scell_recv.h"
#include "phy_common.h"
@ -281,6 +282,7 @@ private:
phy_common* worker_com;
prach* prach_buffer;
async_scell_recv_vector* scell_sync;
srslte::channel* channel_emulator = nullptr;
// Object for synchronization of the primary cell
srslte_ue_sync_t ue_sync;

View File

@ -147,6 +147,13 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("gw.ip_devname", bpo::value<string>(&args->stack.gw.tun_dev_name)->default_value("tun_srsue"), "Name of the tun_srsue device")
("gw.ip_netmask", bpo::value<string>(&args->stack.gw.tun_dev_netmask)->default_value("255.255.255.0"), "Netmask of the tun_srsue device")
/* Channel emulator section */
("channel.dl.enable", bpo::value<bool>(&args->phy.dl_channel_args.enable)->default_value(false), "Enable/Disable internal Downlink channel emulator")
("channel.dl.fading_model", bpo::value<std::string>(&args->phy.dl_channel_args.fading_model)->default_value("none"), "Fading model (none, EPA5, EVA70, ETU300, etc)")
("channel.dl.delay_period", bpo::value<uint32_t >(&args->phy.dl_channel_args.delay_period_s)->default_value(3600), "Delay period in seconds (integer)")
("channel.dl.delay_maximum_us", bpo::value<float >(&args->phy.dl_channel_args.delay_max_us)->default_value(100.0f), "Maximum delay in microseconds")
("channel.dl.delay_minimum_us", bpo::value<float >(&args->phy.dl_channel_args.delay_min_us)->default_value(0.0f), "Maximum delay in microseconds")
/* Expert section */
("expert.phy.worker_cpu_mask",
bpo::value<int>(&args->phy.worker_cpu_mask)->default_value(-1),

View File

@ -21,6 +21,7 @@
#include "srsue/hdr/phy/sync.h"
#include "srslte/common/log.h"
#include "srslte/phy/channel/channel.h"
#include "srslte/srslte.h"
#include "srsue/hdr/phy/sf_worker.h"
#include <algorithm>
@ -91,6 +92,11 @@ void sync::init(radio_interface_phy* _radio,
return;
}
if (worker_com->args->dl_channel_args.enable) {
channel_emulator = new srslte::channel(worker_com->args->dl_channel_args,
worker_com->args->nof_rx_ant * worker_com->args->nof_rx_ant);
}
nof_workers = workers_pool->get_nof_workers();
worker_com->set_nof_workers(nof_workers);
@ -128,6 +134,11 @@ sync::~sync()
}
pthread_mutex_destroy(&rrc_mutex);
srslte_ue_sync_free(&ue_sync);
// Destroy channel emulator if created
if (channel_emulator) {
delete channel_emulator;
}
}
}
@ -925,6 +936,11 @@ void sync::get_current_cell(srslte_cell_t* cell, uint32_t* earfcn)
int sync::radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time)
{
if (radio_h->rx_now(0, data, nsamples, rx_time)) {
if (channel_emulator && rx_time) {
channel_emulator->set_srate(current_srate);
channel_emulator->run(data, data, nsamples, *rx_time);
}
int offset = nsamples - current_sflen;
if (abs(offset) < 10 && offset != 0) {
next_radio_offset[0] = offset;

View File

@ -179,6 +179,25 @@ imei = 353490069873319
[gui]
enable = false
#####################################################################
# Channel emulator options:
# dl.enable: Enable/Disable internal Downlink channel emulator
#
# -- Fading emulator
# dl.fading_model: Fading model (none, EPA5, EVA70, ETU300, etc)
#
# -- Delay Emulator: d(t) = d_min + (d_max - d_min) * sin(2pi*t/period) / 2
# dl.delay_period: Delay period in seconds (integer).
# dl.delay_maximum_us: Maximum delay in microseconds
# dl.delay_minumum_us: Minimum delay in microseconds
#####################################################################
[channel]
#dl.enable = false
#dl.fading_model = none
#dl.delay_period = 3600
#dl.delay_maximum_us = 100
#dl.delay_minimum_us = 10
#####################################################################
# Expert configuration options
#