Fixes for vrtsim
- Allow client to exit cleanly if server is down - Ensure timing_thread is joined only once avoiding exit_function loop - Free noise_device - Save previously sent samples for channel modelling
This commit is contained in:
@@ -228,9 +228,6 @@ IQChannelErrorType shm_td_iq_channel_rx(ShmTDIQChannel *channel,
|
|||||||
void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, size_t num_samples)
|
void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, size_t num_samples)
|
||||||
{
|
{
|
||||||
ShmTDIQChannelData *data = channel->data;
|
ShmTDIQChannelData *data = channel->data;
|
||||||
if (channel->type != IQ_CHANNEL_TYPE_SERVER) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (data->is_connected == false) {
|
if (data->is_connected == false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||||
* contact@openairinterface.org
|
* contact@openairinterface.org
|
||||||
*/
|
*/
|
||||||
|
#include "assertions.h"
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "noise_device.h"
|
#include "noise_device.h"
|
||||||
@@ -74,7 +75,8 @@ void init_noise_device(float noise_power)
|
|||||||
void free_noise_device(void)
|
void free_noise_device(void)
|
||||||
{
|
{
|
||||||
state.running = false;
|
state.running = false;
|
||||||
pthread_join(state.noise_device_thread, NULL);
|
int ret = pthread_join(state.noise_device_thread, NULL);
|
||||||
|
AssertFatal(ret == 0, "pthread_join failed: %d, errno %d (%s)\n", ret, errno, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_noise_vector(float *noise_vector, int length)
|
void get_noise_vector(float *noise_vector, int length)
|
||||||
|
|||||||
+41
-8
@@ -19,6 +19,7 @@
|
|||||||
* contact@openairinterface.org
|
* contact@openairinterface.org
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "PHY/TOOLS/tools_defs.h"
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
@@ -50,7 +51,8 @@
|
|||||||
// Simulator role
|
// Simulator role
|
||||||
typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role;
|
typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role;
|
||||||
|
|
||||||
#define NUM_CHANMOD_THREADS 1
|
#define MAX_NUM_ANTENNAS_TX 4
|
||||||
|
#define MAX_CHANNEL_LENGTH (1 << 20)
|
||||||
|
|
||||||
#define ROLE_CLIENT_STRING "client"
|
#define ROLE_CLIENT_STRING "client"
|
||||||
#define ROLE_SERVER_STRING "server"
|
#define ROLE_SERVER_STRING "server"
|
||||||
@@ -112,6 +114,9 @@ typedef struct {
|
|||||||
Actor_t *channel_modelling_actors;
|
Actor_t *channel_modelling_actors;
|
||||||
} vrtsim_state_t;
|
} vrtsim_state_t;
|
||||||
|
|
||||||
|
// Sample history for channel impulse response
|
||||||
|
static c16_t saved_samples[MAX_NUM_ANTENNAS_TX][MAX_CHANNEL_LENGTH] __attribute__((aligned(32))) = {0};
|
||||||
|
|
||||||
static void histogram_add(histogram_t *histogram, double diff)
|
static void histogram_add(histogram_t *histogram, double diff)
|
||||||
{
|
{
|
||||||
histogram->num_samples++;
|
histogram->num_samples++;
|
||||||
@@ -149,6 +154,16 @@ static void load_channel_model(vrtsim_state_t *vrtsim_state)
|
|||||||
vrtsim_state->tx_bw);
|
vrtsim_state->tx_bw);
|
||||||
char *model_name = vrtsim_state->role == ROLE_CLIENT ? "client_tx_channel_model" : "server_tx_channel_model";
|
char *model_name = vrtsim_state->role == ROLE_CLIENT ? "client_tx_channel_model" : "server_tx_channel_model";
|
||||||
vrtsim_state->channel_desc = find_channel_desc_fromname(model_name);
|
vrtsim_state->channel_desc = find_channel_desc_fromname(model_name);
|
||||||
|
AssertFatal(vrtsim_state->channel_desc != NULL,
|
||||||
|
"Could not find model name %s. Make sure it is present in the config file",
|
||||||
|
model_name);
|
||||||
|
LOG_I(HW,
|
||||||
|
"Channel model %s parameters: path_loss_dB=%.2f, nb_tx=%d, nb_rx=%d, channel_length=%d\n",
|
||||||
|
model_name,
|
||||||
|
vrtsim_state->channel_desc->path_loss_dB,
|
||||||
|
vrtsim_state->channel_desc->nb_tx,
|
||||||
|
vrtsim_state->channel_desc->nb_rx,
|
||||||
|
vrtsim_state->channel_desc->channel_length);
|
||||||
random_channel(vrtsim_state->channel_desc, 0);
|
random_channel(vrtsim_state->channel_desc, 0);
|
||||||
AssertFatal(vrtsim_state->channel_desc != NULL, "Could not find channel model %s\n", model_name);
|
AssertFatal(vrtsim_state->channel_desc != NULL, "Could not find channel model %s\n", model_name);
|
||||||
}
|
}
|
||||||
@@ -376,7 +391,7 @@ static int vrtsim_write_internal(vrtsim_state_t *vrtsim_state,
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
vrtsim_state_t *vrtsim_state;
|
vrtsim_state_t *vrtsim_state;
|
||||||
openair0_timestamp timestamp;
|
openair0_timestamp timestamp;
|
||||||
c16_t *samples[4];
|
c16_t *samples[MAX_NUM_ANTENNAS_TX];
|
||||||
int nsamps;
|
int nsamps;
|
||||||
int nbAnt;
|
int nbAnt;
|
||||||
int flags;
|
int flags;
|
||||||
@@ -410,20 +425,19 @@ static void perform_channel_modelling(void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
|
for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
|
||||||
|
c16_t *previous_samples = saved_samples[aatx];
|
||||||
for (int i = 0; i < nsamps; i++) {
|
for (int i = 0; i < nsamps; i++) {
|
||||||
cf_t *impulse_response = channel_impulse_response[aatx];
|
cf_t *impulse_response = channel_impulse_response[aatx];
|
||||||
for (int l = 0; l < channel_desc->channel_length; l++) {
|
for (int l = 0; l < channel_desc->channel_length; l++) {
|
||||||
int idx = i - l;
|
int idx = i - l;
|
||||||
// TODO: Use AVX512 for this
|
// TODO: Use AVX2 for this
|
||||||
// TODO: What are the previously sent samples (for impulse response)
|
c16_t tx_input = idx >= 0 ? input_samples[aatx][idx]
|
||||||
if (idx >= 0) {
|
: previous_samples[(channel_modelling_args->timestamp + i + idx) % MAX_CHANNEL_LENGTH];
|
||||||
c16_t tx_input = input_samples[aatx][idx];
|
|
||||||
samples[i].r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i;
|
samples[i].r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i;
|
||||||
samples[i].i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i;
|
samples[i].i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to c16_t
|
// Convert to c16_t
|
||||||
c16_t samples_out[aligned_nsamps] __attribute__((aligned(64)));
|
c16_t samples_out[aligned_nsamps] __attribute__((aligned(64)));
|
||||||
@@ -462,6 +476,7 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state,
|
|||||||
int nbAnt,
|
int nbAnt,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
|
AssertFatal(nbAnt < MAX_NUM_ANTENNAS_TX, "Number of antennas %d exceeds maximum %d\n", nbAnt, MAX_NUM_ANTENNAS_TX);
|
||||||
for (int aarx = 0; aarx < vrtsim_state->peer_info.num_rx_antennas; aarx++) {
|
for (int aarx = 0; aarx < vrtsim_state->peer_info.num_rx_antennas; aarx++) {
|
||||||
notifiedFIFO_elt_t *task = newNotifiedFIFO_elt(sizeof(channel_modelling_args_t), 0, NULL, perform_channel_modelling);
|
notifiedFIFO_elt_t *task = newNotifiedFIFO_elt(sizeof(channel_modelling_args_t), 0, NULL, perform_channel_modelling);
|
||||||
channel_modelling_args_t *args = (channel_modelling_args_t *)NotifiedFifoData(task);
|
channel_modelling_args_t *args = (channel_modelling_args_t *)NotifiedFifoData(task);
|
||||||
@@ -476,6 +491,23 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state,
|
|||||||
}
|
}
|
||||||
pushNotifiedFIFO(&vrtsim_state->channel_modelling_actors[aarx].fifo, task);
|
pushNotifiedFIFO(&vrtsim_state->channel_modelling_actors[aarx].fifo, task);
|
||||||
}
|
}
|
||||||
|
int start_index = timestamp % MAX_CHANNEL_LENGTH;
|
||||||
|
int end_index = min(start_index + nsamps, MAX_CHANNEL_LENGTH);
|
||||||
|
int cp_nsamps = end_index - start_index;
|
||||||
|
for (int aatx = 0; aatx < nbAnt; aatx++) {
|
||||||
|
c16_t *samples = (c16_t *)samplesVoid[aatx];
|
||||||
|
memcpy(&saved_samples[aatx][start_index], &samples[0], sizeof(c16_t) * cp_nsamps);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end_index < start_index + nsamps) {
|
||||||
|
// wrap around condition, write at beginning of buffer
|
||||||
|
cp_nsamps = nsamps - cp_nsamps; // remaining samples
|
||||||
|
start_index = 0;
|
||||||
|
for (int aatx = 0; aatx < nbAnt; aatx++) {
|
||||||
|
c16_t *samples = (c16_t *)samplesVoid[aatx];
|
||||||
|
memcpy(&saved_samples[aatx][start_index], &samples[0], sizeof(c16_t) * cp_nsamps);
|
||||||
|
}
|
||||||
|
}
|
||||||
return nsamps;
|
return nsamps;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,7 +538,7 @@ static int vrtsim_read(openair0_device *device, openair0_timestamp *ptimestamp,
|
|||||||
static void vrtsim_end(openair0_device *device)
|
static void vrtsim_end(openair0_device *device)
|
||||||
{
|
{
|
||||||
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
|
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
|
||||||
if (vrtsim_state->role == ROLE_SERVER) {
|
if (vrtsim_state->role == ROLE_SERVER && vrtsim_state->run_timing_thread) {
|
||||||
vrtsim_state->run_timing_thread = false;
|
vrtsim_state->run_timing_thread = false;
|
||||||
int ret = pthread_join(vrtsim_state->timing_thread, NULL);
|
int ret = pthread_join(vrtsim_state->timing_thread, NULL);
|
||||||
AssertFatal(ret == 0, "pthread_join() failed: errno: %d, %s\n", errno, strerror(errno));
|
AssertFatal(ret == 0, "pthread_join() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||||
@@ -526,6 +558,7 @@ static void vrtsim_end(openair0_device *device)
|
|||||||
tx_timing->tx_samples_total += tx_timing[i].tx_samples_total;
|
tx_timing->tx_samples_total += tx_timing[i].tx_samples_total;
|
||||||
}
|
}
|
||||||
tx_timing->average_tx_budget /= vrtsim_state->peer_info.num_rx_antennas;
|
tx_timing->average_tx_budget /= vrtsim_state->peer_info.num_rx_antennas;
|
||||||
|
free_noise_device();
|
||||||
}
|
}
|
||||||
// produce 1 second of extra samples so threads can finish
|
// produce 1 second of extra samples so threads can finish
|
||||||
shm_td_iq_channel_produce_samples(vrtsim_state->channel, vrtsim_state->sample_rate);
|
shm_td_iq_channel_produce_samples(vrtsim_state->channel, vrtsim_state->sample_rate);
|
||||||
|
|||||||
Reference in New Issue
Block a user