srsLTE: added efficient integer resampler and srsue/srsenb integration

master
Xavier Arteaga 4 years ago committed by Xavier Arteaga
parent cc469fc7a3
commit 029f36b449

@ -42,6 +42,7 @@ typedef struct {
typedef struct { typedef struct {
std::string type; std::string type;
std::string log_level; std::string log_level;
double srate_hz;
float dl_freq; float dl_freq;
float ul_freq; float ul_freq;
float freq_offset; float freq_offset;

@ -43,6 +43,10 @@
* Reference: * Reference:
*********************************************************************************************/ *********************************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum { SRSLTE_DFT_COMPLEX, SRSLTE_REAL } srslte_dft_mode_t; typedef enum { SRSLTE_DFT_COMPLEX, SRSLTE_REAL } srslte_dft_mode_t;
typedef enum { SRSLTE_DFT_FORWARD, SRSLTE_DFT_BACKWARD } srslte_dft_dir_t; typedef enum { SRSLTE_DFT_FORWARD, SRSLTE_DFT_BACKWARD } srslte_dft_dir_t;
@ -120,4 +124,8 @@ SRSLTE_API void srslte_dft_run_guru_c(srslte_dft_plan_t* plan);
SRSLTE_API void srslte_dft_run_r(srslte_dft_plan_t* plan, const float* in, float* out); SRSLTE_API void srslte_dft_run_r(srslte_dft_plan_t* plan, const float* in, float* out);
#ifdef __cplusplus
}
#endif
#endif // SRSLTE_DFT_H #endif // SRSLTE_DFT_H

@ -0,0 +1,102 @@
/*
* Copyright 2013-2020 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/.
*
*/
/******************************************************************************
* File: resampler.h
*
* Description: Linear and vector interpolation
*
* Reference:
*****************************************************************************/
#ifndef SRSLTE_RESAMPLER_H
#define SRSLTE_RESAMPLER_H
#include <stdbool.h>
#include <stdint.h>
#include "srslte/config.h"
#include "srslte/phy/dft/dft.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Resampler operating modes
*/
typedef enum {
SRSLTE_RESAMPLER_MODE_INTERPOLATE = 0,
SRSLTE_RESAMPLER_MODE_DECIMATE,
} srslte_resampler_mode_t;
/**
* Resampler internal buffers and subcomponents
*/
typedef struct {
srslte_resampler_mode_t mode;
uint32_t ratio;
uint32_t window_sz;
srslte_dft_plan_t fft;
srslte_dft_plan_t ifft;
uint32_t state_len;
cf_t* in_buffer;
cf_t* out_buffer;
cf_t* state;
cf_t* filter;
} srslte_resampler_fft_t;
/**
* Initialise an FFT based resampler which can be configured as decimator or interpolator.
* @param q Object pointer
* @param mode Determines whether the operation mode is decimation or interpolation
* @param ratio Operational ratio
* @return SRSLTE_SUCCES if no error, otherwise an SRSLTE error code
*/
SRSLTE_API int srslte_resampler_fft_init(srslte_resampler_fft_t* q, srslte_resampler_mode_t mode, uint32_t ratio);
/**
* Get delay from the FFT based resampler.
* @param q Object pointer
* @return the delay in number of samples
*/
SRSLTE_API uint32_t srslte_resampler_fft_get_delay(srslte_resampler_fft_t* q);
/**
* Run FFT based resampler in the initiated mode.
* @param q Object pointer, make sure it has been initialised
* @param input Points at the input complex buffer
* @param output Points at the output complex buffer
* @param nsamples Number of samples to apply the processing
*/
SRSLTE_API void srslte_resampler_fft_run(srslte_resampler_fft_t* q, const cf_t* input, cf_t* output, uint32_t nsamples);
/**
* Free FFT based resampler buffers and subcomponents
* @param q Object pointer
*/
SRSLTE_API void srslte_resampler_fft_free(srslte_resampler_fft_t* q);
#ifdef __cplusplus
}
#endif
#endif // SRSLTE_RESAMPLER_H

@ -26,6 +26,7 @@
#include "srslte/common/interfaces_common.h" #include "srslte/common/interfaces_common.h"
#include "srslte/common/log_filter.h" #include "srslte/common/log_filter.h"
#include "srslte/interfaces/radio_interfaces.h" #include "srslte/interfaces/radio_interfaces.h"
#include "srslte/phy/resampling/resampler.h"
#include "srslte/phy/rf/rf.h" #include "srslte/phy/rf/rf.h"
#include "srslte/radio/radio_base.h" #include "srslte/radio/radio_base.h"
#include "srslte/srslte.h" #include "srslte/srslte.h"
@ -104,6 +105,10 @@ private:
phy_interface_radio* phy = nullptr; phy_interface_radio* phy = nullptr;
cf_t* zeros = nullptr; cf_t* zeros = nullptr;
std::array<cf_t*, SRSLTE_MAX_CHANNELS> dummy_buffers; std::array<cf_t*, SRSLTE_MAX_CHANNELS> dummy_buffers;
std::array<std::vector<cf_t>, SRSLTE_MAX_CHANNELS> tx_buffer;
std::array<std::vector<cf_t>, SRSLTE_MAX_CHANNELS> rx_buffer;
std::array<srslte_resampler_fft_t, SRSLTE_MAX_CHANNELS> interpolators = {};
std::array<srslte_resampler_fft_t, SRSLTE_MAX_CHANNELS> decimators = {};
rf_timestamp_t end_of_burst_time = {}; rf_timestamp_t end_of_burst_time = {};
bool is_start_of_burst = false; bool is_start_of_burst = false;
@ -116,6 +121,8 @@ private:
bool continuous_tx = false; bool continuous_tx = false;
double freq_offset = 0.0; double freq_offset = 0.0;
double cur_tx_srate = 0.0; double cur_tx_srate = 0.0;
double cur_rx_srate = 0.0;
double fix_srate_hz = 0.0;
uint32_t nof_antennas = 0; uint32_t nof_antennas = 0;
uint32_t nof_channels = 0; uint32_t nof_channels = 0;
uint32_t nof_channels_x_dev = 0; uint32_t nof_channels_x_dev = 0;

@ -0,0 +1,299 @@
/*
* Copyright 2013-2020 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 <complex.h>
#include <srslte/phy/utils/debug.h>
#include <stdlib.h>
#include <string.h>
#include "srslte/phy/resampling/resampler.h"
#include "srslte/phy/utils/vector.h"
/**
* Raised cosine filter Roll-off
* 0: Frequency sharp, long in time
* 1: Frequency relaxed, short in time
*/
#define RESAMPLER_BETA 0.45
/**
* The FFT size power is determined from the ratio logarithm in base 2 plus the following parameter
*/
#define RESAMPLER_FILTER_SIZE_POW 2
/**
* Lower bound of the filter size for ensuring a minimum of performance
*/
#define RESAMPLER_FILTER_SIZE_MIN 64
int srslte_resampler_fft_init(srslte_resampler_fft_t* q, srslte_resampler_mode_t mode, uint32_t ratio)
{
if (q == NULL || ratio == 0) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Intinialising the resampler is unnecessary
if (ratio == 1) {
q->ratio = 1;
return SRSLTE_ERROR_OUT_OF_BOUNDS;
}
// Make sure interpolator is freed
srslte_resampler_fft_free(q);
// Initialise sizes
uint32_t base_size =
SRSLTE_MAX(RESAMPLER_FILTER_SIZE_MIN, (uint32_t)pow(2, ceilf(log2f(ratio) + RESAMPLER_FILTER_SIZE_POW)));
uint32_t input_fft_size = 0;
uint32_t output_fft_size = 0;
uint32_t high_size = base_size * ratio;
switch (mode) {
case SRSLTE_RESAMPLER_MODE_INTERPOLATE:
input_fft_size = base_size;
output_fft_size = high_size;
break;
case SRSLTE_RESAMPLER_MODE_DECIMATE:
default:
input_fft_size = high_size;
output_fft_size = base_size;
break;
}
q->mode = mode;
q->ratio = ratio;
q->window_sz = input_fft_size / 4;
q->in_buffer = srslte_vec_cf_malloc(high_size);
if (q->in_buffer == NULL) {
return SRSLTE_ERROR;
}
q->out_buffer = srslte_vec_cf_malloc(high_size);
if (q->out_buffer == NULL) {
return SRSLTE_ERROR;
}
int err =
srslte_dft_plan_guru_c(&q->fft, input_fft_size, SRSLTE_DFT_FORWARD, q->in_buffer, q->out_buffer, 1, 1, 1, 1, 1);
if (err != SRSLTE_SUCCESS) {
ERROR("Initialising DFT\n");
return err;
}
err = srslte_dft_plan_guru_c(
&q->ifft, output_fft_size, SRSLTE_DFT_BACKWARD, q->in_buffer, q->out_buffer, 1, 1, 1, 1, 1);
if (err != SRSLTE_SUCCESS) {
ERROR("Initialising DFT\n");
return err;
}
q->state = srslte_vec_cf_malloc(output_fft_size);
if (q->state == NULL) {
return SRSLTE_ERROR;
}
q->filter = srslte_vec_cf_malloc(high_size);
if (q->filter == NULL) {
return SRSLTE_ERROR;
}
// Compute time domain filter coefficients, see raised cosine formula in section "1.2 Impulse Response" of
// https://dspguru.com/dsp/reference/raised-cosine-and-root-raised-cosine-formulas/
double T = (double)1.0;
for (int32_t i = 0; i < high_size; i++) {
double t = ((double)i - (double)high_size / 2.0) / (double)ratio;
double h = 1.0 / T;
if (isnormal(t)) {
h = sin(M_PI * t / T);
h *= cos(M_PI * t * RESAMPLER_BETA / T);
h /= M_PI * t;
h /= 1.0 - 4.0 * pow(RESAMPLER_BETA, 2.0) * pow(t, 2.0) / pow(T, 2.0);
}
q->in_buffer[i] = (float)h;
}
// Compute frequency domain coefficients, since the filter is symmetrical, it does not matter whether FFT or iFFT
if (mode == SRSLTE_RESAMPLER_MODE_INTERPOLATE) {
srslte_dft_run_guru_c(&q->ifft);
} else {
srslte_dft_run_guru_c(&q->fft);
}
// Normalise filter
float norm = 1.0f / (cabsf(q->out_buffer[0]) * (float)input_fft_size);
srslte_vec_sc_prod_cfc(q->out_buffer, norm, q->filter, high_size);
// Zero state
q->state_len = 0;
srslte_vec_cf_zero(q->state, output_fft_size);
return SRSLTE_SUCCESS;
}
static void resampler_fft_interpolate(srslte_resampler_fft_t* q, const cf_t* input, cf_t* output, uint32_t nsamples)
{
uint32_t count = 0;
if (q == NULL || input == NULL || output == NULL) {
return;
}
while (count < nsamples) {
uint32_t n = SRSLTE_MIN(q->window_sz, nsamples - count);
// Copy input samples
srslte_vec_cf_copy(q->in_buffer, &input[count], q->window_sz);
// Pad zeroes
srslte_vec_cf_zero(&q->in_buffer[n], q->fft.size - n);
// Execute FFT
srslte_dft_run_guru_c(&q->fft);
// Replicate input spectrum
for (uint32_t i = 1; i < q->ratio; i++) {
srslte_vec_cf_copy(&q->out_buffer[q->fft.size * i], q->out_buffer, q->fft.size);
}
// Apply filtering
srslte_vec_prod_ccc(q->out_buffer, q->filter, q->in_buffer, q->ifft.size);
// Execute iFFT
srslte_dft_run_guru_c(&q->ifft);
// Add previous state
srslte_vec_sum_ccc(q->out_buffer, q->state, q->out_buffer, q->state_len);
// Copy output
srslte_vec_cf_copy(&output[count * q->ratio], q->out_buffer, n * q->ratio);
// Save current state
q->state_len = q->ifft.size - n * q->ratio;
srslte_vec_cf_copy(q->state, &q->out_buffer[n * q->ratio], q->state_len);
// Increment count
count += n;
}
}
static void resampler_fft_decimate(srslte_resampler_fft_t* q, const cf_t* input, cf_t* output, uint32_t nsamples)
{
uint32_t count = 0;
if (q == NULL || input == NULL || output == NULL) {
return;
}
while (count < nsamples) {
uint32_t n = SRSLTE_MIN(q->window_sz, nsamples - count);
// Copy input samples
srslte_vec_cf_copy(q->in_buffer, &input[count], q->window_sz);
// Pad zeroes
srslte_vec_cf_zero(&q->in_buffer[n], q->fft.size - n);
// Execute FFT
srslte_dft_run_guru_c(&q->fft);
// Apply filtering and cut
srslte_vec_prod_ccc(q->out_buffer, q->filter, q->in_buffer, q->ifft.size / 2);
srslte_vec_prod_ccc(&q->out_buffer[q->fft.size - q->ifft.size / 2],
&q->filter[q->fft.size - q->ifft.size / 2],
&q->in_buffer[q->ifft.size / 2],
q->ifft.size / 2);
// Execute iFFT
srslte_dft_run_guru_c(&q->ifft);
// Add previous state
srslte_vec_sum_ccc(q->out_buffer, q->state, q->out_buffer, q->state_len);
// Copy output
srslte_vec_cf_copy(&output[count / q->ratio], q->out_buffer, n / q->ratio);
// Save current state
q->state_len = q->ifft.size - n / q->ratio;
srslte_vec_cf_copy(q->state, &q->out_buffer[n / q->ratio], q->state_len);
// Increment count
count += n;
}
}
void srslte_resampler_fft_run(srslte_resampler_fft_t* q, const cf_t* input, cf_t* output, uint32_t nsamples)
{
if (q == NULL) {
return;
}
// If the ratio is unset (0) or 1, copy samples and return
if (q->ratio < 2) {
srslte_vec_cf_copy(output, input, nsamples);
return;
}
switch (q->mode) {
case SRSLTE_RESAMPLER_MODE_INTERPOLATE:
resampler_fft_interpolate(q, input, output, nsamples);
break;
case SRSLTE_RESAMPLER_MODE_DECIMATE:
default:
resampler_fft_decimate(q, input, output, nsamples);
break;
}
}
void srslte_resampler_fft_free(srslte_resampler_fft_t* q)
{
if (q == NULL) {
return;
}
srslte_dft_plan_free(&q->fft);
srslte_dft_plan_free(&q->ifft);
if (q->state) {
free(q->state);
}
if (q->in_buffer) {
free(q->in_buffer);
}
if (q->out_buffer) {
free(q->out_buffer);
}
if (q->filter) {
free(q->filter);
}
memset(q, 0, sizeof(srslte_resampler_fft_t));
}
uint32_t srslte_resampler_fft_get_delay(srslte_resampler_fft_t* q)
{
if (q == NULL) {
return UINT32_MAX;
}
return q->ifft.size / 2;
}

@ -30,5 +30,16 @@ target_link_libraries(resample_arb_bench srslte_phy)
add_test(resample resample_arb_test) add_test(resample resample_arb_test)
########################################################################
# FFT based interpolate/decimate
########################################################################
add_executable(resampler_test resampler_test.c)
target_link_libraries(resampler_test srslte_phy)
add_test(resampler_test_2 resampler_test -s 1920 -r 2 -f 2)
add_test(resampler_test_3 resampler_test -s 1920 -r 2 -f 3)
add_test(resampler_test_6 resampler_test -s 1920 -r 2 -f 6)
add_test(resampler_test_8 resampler_test -s 1920 -r 2 -f 8)
add_test(resampler_test_12 resampler_test -s 1920 -r 2 -f 12)
add_test(resampler_test_16 resampler_test -s 1920 -r 2 -f 16)

@ -0,0 +1,118 @@
/*
* Copyright 2013-2020 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/resampling/resampler.h"
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
#include <getopt.h>
#include <stdlib.h>
#include <sys/time.h>
static uint32_t buffer_size = 1920;
static uint32_t factor = 2;
static uint32_t repetitions = 2;
static void usage(char* prog)
{
printf("Usage: %s [sfr]\n", prog);
printf("\t-s Buffer size [Default %d]\n", buffer_size);
printf("\t-f Buffer size [Default %d]\n", factor);
printf("\t-f r [Default %d]\n", repetitions);
}
static void parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "sfr")) != -1) {
switch (opt) {
case 's':
buffer_size = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'f':
factor = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'r':
repetitions = (uint32_t)strtol(argv[optind], NULL, 10);
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int main(int argc, char** argv)
{
struct timeval t[3] = {};
srslte_resampler_fft_t interp = {};
srslte_resampler_fft_t decim = {};
parse_args(argc, argv);
cf_t* src = srslte_vec_cf_malloc(buffer_size);
cf_t* interpolated = srslte_vec_cf_malloc(buffer_size * factor);
cf_t* decimated = srslte_vec_cf_malloc(buffer_size);
if (srslte_resampler_fft_init(&interp, SRSLTE_RESAMPLER_MODE_INTERPOLATE, factor)) {
return SRSLTE_ERROR;
}
if (srslte_resampler_fft_init(&decim, SRSLTE_RESAMPLER_MODE_DECIMATE, factor)) {
return SRSLTE_ERROR;
}
srslte_vec_cf_zero(src, buffer_size);
srslte_vec_gen_sine(1.0f, 0.01f, src, buffer_size / 10);
gettimeofday(&t[1], NULL);
for (uint32_t r = 0; r < repetitions; r++) {
srslte_resampler_fft_run(&interp, src, interpolated, buffer_size);
srslte_resampler_fft_run(&decim, interpolated, decimated, buffer_size * factor);
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
uint64_t duration_us = (uint64_t)(t[0].tv_sec * 1000000UL + t[0].tv_usec);
printf("Done %.1f Msps\n", factor * buffer_size * repetitions / (double)duration_us);
// printf("interp=");
// srslte_vec_fprint_c(stdout, interpolated, buffer_size * factor);
// Check error
uint32_t delay = srslte_resampler_fft_get_delay(&decim) * 2;
uint32_t nsamples = buffer_size - delay;
srslte_vec_sub_ccc(src, &decimated[delay], interpolated, nsamples);
float mse = sqrtf(srslte_vec_avg_power_cf(interpolated, nsamples));
printf("MSE: %f\n", mse);
// printf("src=");
// srslte_vec_fprint_c(stdout, src, nsamples);
// printf("decim=");
// srslte_vec_fprint_c(stdout, &decimated[delay], nsamples);
srslte_resampler_fft_free(&interp);
srslte_resampler_fft_free(&decim);
free(src);
free(interpolated);
free(decimated);
return (mse < 0.1f) ? SRSLTE_SUCCESS : SRSLTE_ERROR;
}

@ -54,11 +54,12 @@ radio::~radio()
zeros = nullptr; zeros = nullptr;
} }
for (uint32_t i = 0; i < SRSLTE_MAX_CHANNELS; i++) { for (srslte_resampler_fft_t& q : interpolators) {
if (dummy_buffers[i]) { srslte_resampler_fft_free(&q);
free(dummy_buffers[i]);
dummy_buffers[i] = nullptr;
} }
for (srslte_resampler_fft_t& q : decimators) {
srslte_resampler_fft_free(&q);
} }
} }
@ -96,6 +97,7 @@ int radio::init(const rf_args_t& args, phy_interface_radio* phy_)
nof_channels = args.nof_antennas * args.nof_carriers; nof_channels = args.nof_antennas * args.nof_carriers;
nof_antennas = args.nof_antennas; nof_antennas = args.nof_antennas;
nof_carriers = args.nof_carriers; nof_carriers = args.nof_carriers;
fix_srate_hz = args.srate_hz;
cur_tx_freqs.resize(nof_carriers); cur_tx_freqs.resize(nof_carriers);
cur_rx_freqs.resize(nof_carriers); cur_rx_freqs.resize(nof_carriers);
@ -259,6 +261,17 @@ bool radio::start_agc(bool tx_gain_same_rx)
bool radio::rx_now(rf_buffer_interface& buffer, rf_timestamp_interface& rxd_time) bool radio::rx_now(rf_buffer_interface& buffer, rf_timestamp_interface& rxd_time)
{ {
bool ret = true; bool ret = true;
rf_buffer_t buffer_rx;
uint32_t ratio = SRSLTE_MAX(1, decimators[0].ratio);
// If the interpolator have been set, interpolate
for (uint32_t ch = 0; ch < nof_channels; ch++) {
// Use rx buffer if decimator is required
buffer_rx.set(ch, ratio > 1 ? rx_buffer[ch].data() : buffer.get(ch));
}
// Set new buffer size
buffer_rx.set_nof_samples(buffer.get_nof_samples() * ratio);
if (not radio_is_streaming) { if (not radio_is_streaming) {
for (srslte_rf_t& rf_device : rf_devices) { for (srslte_rf_t& rf_device : rf_devices) {
@ -275,7 +288,14 @@ bool radio::rx_now(rf_buffer_interface& buffer, rf_timestamp_interface& rxd_time
} }
for (uint32_t device_idx = 0; device_idx < (uint32_t)rf_devices.size(); device_idx++) { for (uint32_t device_idx = 0; device_idx < (uint32_t)rf_devices.size(); device_idx++) {
ret &= rx_dev(device_idx, buffer, rxd_time.get_ptr(device_idx)); ret &= rx_dev(device_idx, buffer_rx, rxd_time.get_ptr(device_idx));
}
// Perform decimation
if (ratio > 1) {
for (uint32_t ch = 0; ch < nof_channels; ch++) {
srslte_resampler_fft_run(&decimators[ch], buffer_rx.get(ch), buffer.get(ch), buffer_rx.get_nof_samples());
}
} }
return ret; return ret;
@ -342,6 +362,20 @@ bool radio::tx(rf_buffer_interface& buffer, const rf_timestamp_interface& tx_tim
{ {
bool ret = true; bool ret = true;
// If the interpolator have been set, interpolate
if (interpolators[0].ratio > 1) {
for (uint32_t ch = 0; ch < nof_channels; ch++) {
// Perform actual interpolation
srslte_resampler_fft_run(&interpolators[ch], buffer.get(ch), tx_buffer[ch].data(), buffer.get_nof_samples());
// Set the buffer pointer
buffer.set(ch, tx_buffer[ch].data());
}
// Set new buffer size
buffer.set_nof_samples(buffer.get_nof_samples() * interpolators[0].ratio);
}
for (uint32_t device_idx = 0; device_idx < (uint32_t)rf_devices.size(); device_idx++) { for (uint32_t device_idx = 0; device_idx < (uint32_t)rf_devices.size(); device_idx++) {
ret &= tx_dev(device_idx, buffer, tx_time.get(device_idx)); ret &= tx_dev(device_idx, buffer, tx_time.get(device_idx));
} }
@ -573,8 +607,29 @@ void radio::set_rx_srate(const double& srate)
if (!is_initialized) { if (!is_initialized) {
return; return;
} }
// If fix sampling rate...
if (std::isnormal(fix_srate_hz)) {
// If the sampling rate was not set, set it
if (not std::isnormal(cur_rx_srate)) {
for (srslte_rf_t& rf_device : rf_devices) {
cur_rx_srate = srslte_rf_set_rx_srate(&rf_device, fix_srate_hz);
}
}
// Update decimators
uint32_t ratio = (uint32_t)ceil(cur_rx_srate / srate);
for (uint32_t ch = 0; ch < nof_channels; ch++) {
srslte_resampler_fft_init(&decimators[ch], SRSLTE_RESAMPLER_MODE_DECIMATE, ratio);
if (rx_buffer[ch].empty()) {
rx_buffer[ch].resize(SRSLTE_SF_LEN_MAX * 5);
}
}
} else {
for (srslte_rf_t& rf_device : rf_devices) { for (srslte_rf_t& rf_device : rf_devices) {
srslte_rf_set_rx_srate(&rf_device, srate); cur_rx_srate = srslte_rf_set_rx_srate(&rf_device, srate);
}
} }
} }
@ -794,9 +849,29 @@ void radio::set_tx_srate(const double& srate)
return; return;
} }
// If fix sampling rate...
if (std::isnormal(fix_srate_hz)) {
// If the sampling rate was not set, set it
if (not std::isnormal(cur_tx_srate)) {
for (srslte_rf_t& rf_device : rf_devices) {
cur_tx_srate = srslte_rf_set_tx_srate(&rf_device, fix_srate_hz);
}
}
// Update interpolators
uint32_t ratio = (uint32_t)ceil(cur_tx_srate / srate);
for (uint32_t ch = 0; ch < nof_channels; ch++) {
srslte_resampler_fft_init(&interpolators[ch], SRSLTE_RESAMPLER_MODE_INTERPOLATE, ratio);
if (tx_buffer[ch].empty()) {
tx_buffer[ch].resize(5 * SRSLTE_SF_LEN_MAX);
}
}
} else {
for (srslte_rf_t& rf_device : rf_devices) { for (srslte_rf_t& rf_device : rf_devices) {
cur_tx_srate = srslte_rf_set_tx_srate(&rf_device, srate); cur_tx_srate = srslte_rf_set_tx_srate(&rf_device, srate);
} }
}
// Get calibrated advanced // Get calibrated advanced
tx_adv_sec = get_dev_cal_tx_adv_sec(std::string(srslte_rf_name(&rf_devices[0]))); tx_adv_sec = get_dev_cal_tx_adv_sec(std::string(srslte_rf_name(&rf_devices[0])));

@ -46,6 +46,7 @@ struct phy_args_t {
std::string type; std::string type;
srslte::phy_log_args_t log; srslte::phy_log_args_t log;
float sampling_rate_hz = 0.0f;
float max_prach_offset_us = 10; float max_prach_offset_us = 10;
int pusch_max_its = 10; int pusch_max_its = 10;
bool pusch_8bit_decoder = false; bool pusch_8bit_decoder = false;

@ -87,6 +87,7 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("enb_files.drb_config", bpo::value<string>(&args->enb_files.drb_config)->default_value("drb.conf"), "DRB configuration files") ("enb_files.drb_config", bpo::value<string>(&args->enb_files.drb_config)->default_value("drb.conf"), "DRB configuration files")
("rf.dl_earfcn", bpo::value<uint32_t>(&args->enb.dl_earfcn)->default_value(0), "Force Downlink EARFCN for single cell") ("rf.dl_earfcn", bpo::value<uint32_t>(&args->enb.dl_earfcn)->default_value(0), "Force Downlink EARFCN for single cell")
("rf.srate", bpo::value<double>(&args->rf.srate_hz)->default_value(0.0), "Force Tx and Rx sampling rate in Hz")
("rf.rx_gain", bpo::value<float>(&args->rf.rx_gain)->default_value(50), "Front-end receiver gain") ("rf.rx_gain", bpo::value<float>(&args->rf.rx_gain)->default_value(50), "Front-end receiver gain")
("rf.tx_gain", bpo::value<float>(&args->rf.tx_gain)->default_value(70), "Front-end transmitter gain") ("rf.tx_gain", bpo::value<float>(&args->rf.tx_gain)->default_value(70), "Front-end transmitter gain")
("rf.dl_freq", bpo::value<float>(&args->rf.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)") ("rf.dl_freq", bpo::value<float>(&args->rf.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)")

@ -76,6 +76,7 @@ static int parse_args(all_args_t* args, int argc, char* argv[])
("rf.dl_earfcn", bpo::value<string>(&args->phy.dl_earfcn)->default_value("3400"), "Downlink EARFCN list") ("rf.dl_earfcn", bpo::value<string>(&args->phy.dl_earfcn)->default_value("3400"), "Downlink EARFCN list")
("rf.ul_earfcn", bpo::value<string>(&args->phy.ul_earfcn), "Uplink EARFCN list. Optional.") ("rf.ul_earfcn", bpo::value<string>(&args->phy.ul_earfcn), "Uplink EARFCN list. Optional.")
("rf.srate", bpo::value<double>(&args->rf.srate_hz)->default_value(0.0), "Force Tx and Rx sampling rate in Hz")
("rf.freq_offset", bpo::value<float>(&args->rf.freq_offset)->default_value(0), "(optional) Frequency offset") ("rf.freq_offset", bpo::value<float>(&args->rf.freq_offset)->default_value(0), "(optional) Frequency offset")
("rf.dl_freq", bpo::value<float>(&args->phy.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)") ("rf.dl_freq", bpo::value<float>(&args->phy.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)")
("rf.ul_freq", bpo::value<float>(&args->phy.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)") ("rf.ul_freq", bpo::value<float>(&args->phy.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)")

Loading…
Cancel
Save