Added High Speed Train model to channel emulator

This commit is contained in:
Xavier Arteaga 2019-07-23 15:58:03 +02:00 committed by Xavier Arteaga
parent 54974d935e
commit d7c1a0bda9
6 changed files with 325 additions and 0 deletions

View File

@ -25,6 +25,7 @@
#include "delay.h"
#include "fading.h"
#include "rlf.h"
#include "hst.h"
#include <memory>
#include <srslte/config.h>
#include <srslte/srslte.h>
@ -43,6 +44,12 @@ public:
bool fading_enable = false;
std::string fading_model = "none";
// High Speed Train options
bool hst_enable = false;
float hst_fd_hz = 750.0f;
float hst_period_s = 7.2f;
float hst_init_time_s = 7.2f;
// Delay options
bool delay_enable = false;
float delay_min_us = 10;
@ -63,6 +70,7 @@ public:
private:
srslte_channel_fading_t* fading[SRSLTE_MAX_PORTS] = {};
srslte_channel_delay_t* delay[SRSLTE_MAX_PORTS] = {};
srslte_channel_hst_t* hst = nullptr; // HST has no buffers / no multiple instance is required
srslte_channel_rlf_t* rlf = nullptr; // RLF has no buffers / no multiple instance is required
cf_t* buffer_in = nullptr;
cf_t* buffer_out = nullptr;

View File

@ -0,0 +1,62 @@
/*
* 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_HST_H_
#define SRSLTE_HST_H_
#include <srslte/srslte.h>
typedef struct {
// System parameters
uint32_t srate_hz; // Sampling rate
// Model Parameters
float fd_hz; // Maximum Doppler Frequency
float ds_m; // eNb distance [m]
float dmin_m; // eNb Rail-track distance [m]
float period_s; // 2 * Ds / speed [s]
float init_time_s; // Time offset [s]
// State
float fs_hz; // Last doppler dispersion [Hz]
} srslte_channel_hst_t;
#ifdef __cplusplus
extern "C" {
#endif
SRSLTE_API int srslte_channel_hst_init(srslte_channel_hst_t *q, float fd_hz, float period_d, float init_time_s);
SRSLTE_API void srslte_channel_hst_update_srate(srslte_channel_hst_t *q, uint32_t srate);
SRSLTE_API void srslte_channel_hst_execute(srslte_channel_hst_t *q,
cf_t *in,
cf_t *out,
uint32_t len,
const srslte_timestamp_t *ts);
SRSLTE_API void srslte_channel_hst_free(srslte_channel_hst_t *q);
#ifdef __cplusplus
}
#endif
#endif //SRSLTE_HST_H_

View File

@ -62,6 +62,13 @@ channel::channel(const channel::args_t& channel_args, uint32_t _nof_ports)
}
}
// Create high speed train
if (channel_args.hst_enable && ret == SRSLTE_SUCCESS) {
hst = (srslte_channel_hst_t*)calloc(sizeof(srslte_channel_hst_t), 1);
srslte_channel_hst_init(hst, channel_args.hst_fd_hz, channel_args.hst_period_s, channel_args.hst_init_time_s);
}
// Create Radio Link Failure simulator
if (channel_args.rlf_enable && ret == SRSLTE_SUCCESS) {
rlf = (srslte_channel_rlf_t*)calloc(sizeof(srslte_channel_rlf_t), 1);
srslte_channel_rlf_init(rlf, channel_args.rlf_t_on_ms, channel_args.rlf_t_off_ms);
@ -82,6 +89,11 @@ channel::~channel()
free(buffer_out);
}
if (hst) {
srslte_channel_hst_free(hst);
free(hst);
}
if (rlf) {
srslte_channel_rlf_free(rlf);
free(rlf);
@ -121,6 +133,11 @@ void channel::run(cf_t* in[SRSLTE_MAX_PORTS], cf_t* out[SRSLTE_MAX_PORTS], uint3
memcpy(buffer_in, buffer_out, sizeof(cf_t) * len);
}
if (hst) {
srslte_channel_hst_execute(hst, buffer_in, buffer_out, len, &t);
memcpy(buffer_in, buffer_out, sizeof(cf_t) * len);
}
if (rlf) {
srslte_channel_rlf_execute(rlf, buffer_in, buffer_out, len, &t);
memcpy(buffer_in, buffer_out, sizeof(cf_t) * len);
@ -156,5 +173,9 @@ void channel::set_srate(uint32_t srate)
}
current_srate = srate;
}
if (hst) {
srslte_channel_hst_update_srate(hst, srate);
}
}
}

82
lib/src/phy/channel/hst.c Normal file
View File

@ -0,0 +1,82 @@
/*
* 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 "srslte/phy/channel/hst.h"
int srslte_channel_hst_init(srslte_channel_hst_t *q, float fd_hz, float period_d, float init_time_s) {
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q) {
q->fd_hz = fd_hz; // Hz
q->ds_m = 300.0f; // m
q->dmin_m = 2.0f; // m
q->period_s = period_d; // s
q->init_time_s = init_time_s; // s
q->fs_hz = NAN;
ret = SRSLTE_SUCCESS;
}
return ret;
}
void srslte_channel_hst_update_srate(srslte_channel_hst_t *q, uint32_t srate) {
if (q) {
q->srate_hz = srate;
}
}
void srslte_channel_hst_execute(srslte_channel_hst_t *q, cf_t *in, cf_t *out, uint32_t len, const srslte_timestamp_t *ts) {
if (q) {
if (q->srate_hz) {
// Convert period from seconds to samples
uint64_t period_nsamples = (uint64_t) roundf(q->period_s * q->srate_hz);
// Convert timestamp to samples
uint64_t ts_nsamples = srslte_timestamp_uint64(ts, q->srate_hz);
// Calculate time modulus in period
uint64_t mod_t_nsamples = ts_nsamples - period_nsamples * (ts_nsamples / period_nsamples);
float t = (float) mod_t_nsamples / (float) q->srate_hz;
float costheta = 0;
if (0 <= t && t <= q->period_s / 2.0f) {
float num = q->period_s / 4.0f - t;
float den = sqrtf(powf(q->dmin_m * q->period_s / (q->ds_m * 2), 2.0f) + powf(num, 2.0f));
costheta = num / den;
} else if (q->period_s / 2.0f < t && t < q->period_s) {
float num = -1.5f / 2.0f * q->period_s + t;
float den = sqrtf(powf(q->dmin_m * q->period_s / (q->ds_m * 2), 2.0f) + powf(num, 2.0f));
costheta = num / den;
}
// Calculate doppler shift
q->fs_hz = q->fd_hz * costheta;
// Apply doppler shift, assume the doppler does not vary in a sub-frame
srslte_vec_apply_cfo(in, -q->fs_hz / q->srate_hz, out, len);
}
}
}
void srslte_channel_hst_free(srslte_channel_hst_t *q) {
bzero(q, sizeof(srslte_channel_hst_t));
}

View File

@ -33,3 +33,7 @@ add_executable(delay_channel_test delay_channel_test.c)
target_link_libraries(delay_channel_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
add_test(delay_channel_test delay_channel_test -m 10 -M 100 -t 1000 -T 1 -s 1.92e6)
add_executable(hst_channel_test hst_channel_test.c)
target_link_libraries(hst_channel_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
add_test(hst_channel_test hst_channel_test -f 750 -t 7.2 -i 0 -T 1 -s 1.92e6)

View File

@ -0,0 +1,148 @@
/*
* 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 "srslte/phy/utils/vector.h"
#include <srslte/phy/channel/hst.h>
#include <srslte/phy/utils/debug.h>
#include <unistd.h>
static srslte_channel_hst_t hst = {};
static float fd_hz = 750;
static float period_s = 7.2;
static float init_time_s = 0;
static uint32_t srate_hz = 1920000;
static uint32_t sim_time_periods = 1;
#define INPUT_TYPE 0 /* 0: Dirac Delta; Otherwise: Random*/
static void usage(char* prog)
{
printf("Usage: %s [mMtsT]\n", prog);
printf("\t-f Doppler frequency [Default %.1f]\n", fd_hz);
printf("\t-t Period in seconds: [Default %.1f]\n", period_s);
printf("\t-i Initial time in seconds: [Default %.1f]\n", init_time_s);
printf("\t-s Sampling rate in Hz: [Default %d]\n", srate_hz);
printf("\t-T Simulation Time in periods: [Default %d]\n", sim_time_periods);
}
static void parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "ftisT")) != -1) {
switch (opt) {
case 'f':
fd_hz = strtof(argv[optind], NULL);
break;
case 't':
period_s = strtof(argv[optind], NULL);
break;
case 'i':
init_time_s = strtof(argv[optind], NULL);
break;
case 's':
srate_hz = (uint32_t)strtof(argv[optind], NULL);
break;
case 'T':
sim_time_periods = (uint32_t)strtol(argv[optind], NULL, 10);
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int main(int argc, char** argv)
{
int ret = SRSLTE_SUCCESS;
cf_t* input_buffer = NULL;
cf_t* output_buffer = NULL;
srslte_timestamp_t ts = {}; // Initialised to zero
struct timeval t[3] = {};
// Parse arguments
parse_args(argc, argv);
// Initialise buffers
uint32_t size = srate_hz / 1000; // 1 ms samples
input_buffer = srslte_vec_malloc(sizeof(cf_t) * size);
output_buffer = srslte_vec_malloc(sizeof(cf_t) * size);
if (!input_buffer || !output_buffer) {
fprintf(stderr, "Error: Allocating memory\n");
ret = SRSLTE_ERROR;
}
// Generate random samples
srslte_vec_gen_sine(1.0f, 0.0f, input_buffer, size);
// Initialise delay channel
if (ret == SRSLTE_SUCCESS) {
ret = srslte_channel_hst_init(&hst, fd_hz, period_s, init_time_s);
srslte_channel_hst_update_srate(&hst, srate_hz);
}
// Run actual test
gettimeofday(&t[1], NULL);
for (int i = 0; i < sim_time_periods && ret == SRSLTE_SUCCESS; i++) {
for (int j = 0; j < 1000 * period_s; j++) {
// Run delay channel
srslte_channel_hst_execute(&hst, input_buffer, output_buffer, size, &ts);
// Increment timestamp 1ms
srslte_timestamp_add(&ts, 0, 0.001);
float ideal_freq = hst.fs_hz;
float meas_freq = srslte_vec_estimate_frequency(output_buffer, size) * srate_hz;
if (fabsf(ideal_freq- meas_freq) > 0.5f) {
printf("Error [%03d.%03d] fs = [%6.1f | %6.1f] Hz\n", i, j, ideal_freq, meas_freq);
return SRSLTE_ERROR;
}
}
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
// Free
srslte_channel_hst_free(&hst);
if (input_buffer) {
free(input_buffer);
}
if (output_buffer) {
free(output_buffer);
}
uint64_t nof_samples = sim_time_periods * 1000 * period_s * size;
double elapsed_us = t[0].tv_sec * 1e6 + t[0].tv_usec;
// Print result and exit
printf("Test fd=%.1fHz; period=%.1fs; init_time=%.1fs; srate_hz=%d; periods=%d; %s ... %.1f MSps\n",
fd_hz,
period_s,
init_time_s,
srate_hz,
sim_time_periods,
(ret == SRSLTE_SUCCESS) ? "Passed" : "Failed",
(double)nof_samples / elapsed_us);
exit(ret);
}