From b5aad5956cee78bfd5d2bb7ead5e38ff1874217b Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 3 Dec 2025 15:06:31 +0100 Subject: [PATCH] vrtsim: rewrite sample history Limit sample history to 256 samples and copy it into each channel modelling task instead of relying on globally available buffer. This simplifies the code and addressing into the saved samples buffer as well as enabling further optimizations without sacrificing thread safety. --- radio/vrtsim/vrtsim.c | 55 ++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/radio/vrtsim/vrtsim.c b/radio/vrtsim/vrtsim.c index 9e678a5305..01589797d0 100644 --- a/radio/vrtsim/vrtsim.c +++ b/radio/vrtsim/vrtsim.c @@ -54,7 +54,7 @@ typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role; #define MAX_NUM_ANTENNAS_TX 4 -#define MAX_CHANNEL_LENGTH (1 << 20) +#define SAVED_SAMPLES_LEN 256 #define ROLE_CLIENT_STRING "client" #define ROLE_SERVER_STRING "server" @@ -125,9 +125,6 @@ typedef struct { int client_num_rx_antennas; } 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) { histogram->num_samples++; @@ -375,6 +372,7 @@ typedef struct { int nbAnt; int flags; int aarx; + c16_t saved_samples[MAX_NUM_ANTENNAS_TX][SAVED_SAMPLES_LEN]; } channel_modelling_args_t; static void perform_channel_modelling(void *arg) @@ -418,14 +416,13 @@ static void perform_channel_modelling(void *arg) } for (int aatx = 0; aatx < nb_tx_ant; aatx++) { - c16_t *previous_samples = saved_samples[aatx]; for (int i = 0; i < nsamps; i++) { cf_t *impulse_response = channel_impulse_response_p[aatx]; for (int l = 0; l < channel_desc->channel_length; l++) { int idx = i - l; // TODO: Use AVX2 for this c16_t tx_input = idx >= 0 ? input_samples[aatx][idx] - : previous_samples[(channel_modelling_args->timestamp + i + idx) % MAX_CHANNEL_LENGTH]; + : channel_modelling_args->saved_samples[aatx][SAVED_SAMPLES_LEN + idx]; 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; } @@ -469,6 +466,11 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state, int nbAnt, int flags) { + // Sample history for channel impulse response + static c16_t saved_samples[MAX_NUM_ANTENNAS_TX][SAVED_SAMPLES_LEN] __attribute__((aligned(32))) = {0}; + // Indicates what samples are saves in saved_samples + static openair0_timestamp last_timestamp = 0; + 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++) { notifiedFIFO_elt_t *task = newNotifiedFIFO_elt(sizeof(channel_modelling_args_t), 0, NULL, perform_channel_modelling); @@ -482,25 +484,40 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state, for (int i = 0; i < nbAnt; i++) { args->samples[i] = samplesVoid[i]; } + + // Fill in saved_samples + size_t gap_samples = timestamp - last_timestamp; + if (gap_samples > 0) { + size_t gap_samples_needed = min(SAVED_SAMPLES_LEN, gap_samples); + for (int aatx = 0; aatx < nbAnt; aatx++) { + memset(&args->saved_samples[aatx][SAVED_SAMPLES_LEN - gap_samples_needed], 0, sizeof(c16_t) * gap_samples_needed); + if (gap_samples < SAVED_SAMPLES_LEN) { + size_t samples_from_saved = SAVED_SAMPLES_LEN - gap_samples_needed; + memcpy(&args->saved_samples[aatx][0], &saved_samples[aatx][SAVED_SAMPLES_LEN - samples_from_saved], sizeof(c16_t) * samples_from_saved); + } + } + } else { + for (int aatx = 0; aatx < nbAnt; aatx++) + memcpy(&args->saved_samples[aatx][0], saved_samples[aatx], sizeof(c16_t) * SAVED_SAMPLES_LEN); + } + memcpy(args->saved_samples, saved_samples, sizeof(saved_samples)); 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; + // Save samples for next round + if (nsamps < SAVED_SAMPLES_LEN) { 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); + memmove(&saved_samples[aatx][0], &saved_samples[aatx][nsamps], sizeof(c16_t) * (SAVED_SAMPLES_LEN - nsamps)); + memcpy(&saved_samples[aatx][SAVED_SAMPLES_LEN - nsamps], samplesVoid[aatx], sizeof(c16_t) * nsamps); + } + } else { + for (int aatx = 0; aatx < nbAnt; aatx++) { + c16_t* samples = (c16_t*)samplesVoid[aatx]; + memcpy(saved_samples[aatx], &samples[nsamps - SAVED_SAMPLES_LEN], sizeof(c16_t) * (SAVED_SAMPLES_LEN)); } } + + last_timestamp = timestamp + nsamps; return nsamps; }