mirror of https://github.com/pvnis/srsRAN_4G.git
SRSUE: Created delay channel emulator and added fading to the UE
parent
709e769d0d
commit
9ab2b2de81
@ -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
|
@ -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
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
Loading…
Reference in New Issue