Rfsim: Optimization for simple configurations

- Added first beam optimization to combine_tx_buffers.
 - Added first beam & first peer optimization to rfsimulator_read_internal

This results in significant speed up for the first rx beam, first tx
beam and first peer which is the base case with beam simulation disabled.
This commit is contained in:
Bartosz Podrygajlo
2025-12-23 10:05:14 +01:00
parent c587aab6b6
commit 033aed736e
3 changed files with 76 additions and 37 deletions
+1 -1
View File
@@ -235,7 +235,7 @@ void update_channel_model(channel_desc_t *channelDesc, uint64_t TS)
either we regenerate the channel (call again random_channel(desc,0)), or we keep it over subframes either we regenerate the channel (call again random_channel(desc,0)), or we keep it over subframes
legacy: we regenerate each sub frame in UL, and each frame only in DL legacy: we regenerate each sub frame in UL, and each frame only in DL
*/ */
void rxAddInput(const c16_t **input_sig, void rxAddInput(c16_t **input_sig,
cf_t *after_channel_sig, cf_t *after_channel_sig,
int rxAnt, int rxAnt,
channel_desc_t *channelDesc, channel_desc_t *channelDesc,
+1 -1
View File
@@ -24,7 +24,7 @@
#ifndef __RFSIMULATOR_H #ifndef __RFSIMULATOR_H
#define __RFSIMULATOR_H #define __RFSIMULATOR_H
#include <stdbool.h> #include <stdbool.h>
void rxAddInput(const c16_t **input_sig, void rxAddInput(c16_t **input_sig,
cf_t *after_channel_sig, cf_t *after_channel_sig,
int rxAnt, int rxAnt,
channel_desc_t *channelDesc, channel_desc_t *channelDesc,
+74 -35
View File
@@ -1045,17 +1045,18 @@ static std::vector<int> get_beam_ids(uint64_t beam_map)
* @param num_aatx The number of antennas to process. * @param num_aatx The number of antennas to process.
* @param num_samples The number of samples to process. * @param num_samples The number of samples to process.
* @param rx_beam_id Receiver configured beam id for the timestamp * @param rx_beam_id Receiver configured beam id for the timestamp
* @param samples Pointer to the output buffer where combined samples will be stored.
* @return A vector of vectors containing the combined samples for each antenna. * @return A vector of vectors containing the combined samples for each antenna.
*/ */
static std::vector<std::vector<c16_t>> combine_received_beams(rfsimulator_state_t *t, static void combine_received_beams(rfsimulator_state_t *t,
std::queue<rfsim_packet_t *> &received_packets, std::queue<rfsim_packet_t *> &received_packets,
uint64_t start_timestamp, uint64_t start_timestamp,
int num_aatx, int num_aatx,
size_t num_samples, size_t num_samples,
int rx_beam_id) int rx_beam_id,
c16_t **samples)
{ {
// Assume received_packets is ordered by timestamp // Assume received_packets is ordered by timestamp
std::vector<std::vector<c16_t>> ant_buffers(num_aatx, std::vector<c16_t>(num_samples, {0, 0}));
std::queue<rfsim_packet_t *> packets_copy = received_packets; std::queue<rfsim_packet_t *> packets_copy = received_packets;
while (!packets_copy.empty()) { while (!packets_copy.empty()) {
rfsim_packet_t *pkt = packets_copy.front(); rfsim_packet_t *pkt = packets_copy.front();
@@ -1081,16 +1082,38 @@ static std::vector<std::vector<c16_t>> combine_received_beams(rfsimulator_state_
for (int aatx = 0; aatx < num_aatx; aatx++) { for (int aatx = 0; aatx < num_aatx; aatx++) {
c16_t *buffer = (c16_t *)pkt->payload; c16_t *buffer = (c16_t *)pkt->payload;
c16_t *tx_ant_buffer_in = &buffer[(num_aatx * beam + aatx) * pkt->header.size + read_start_idx]; c16_t *tx_ant_buffer_in = &buffer[(num_aatx * beam + aatx) * pkt->header.size + read_start_idx];
for (int s = write_start_idx; s < write_end_idx; s++) { if (beam == 0) {
ant_buffers[aatx][s].r += tx_ant_buffer_in->r * gain_linear; // For the first beam, we can directly copy the samples
ant_buffers[aatx][s].i += tx_ant_buffer_in->i * gain_linear; if (gain_dB == 0.0f) {
tx_ant_buffer_in++; // If gain is 0 dB, we can use memcpy for efficiency
memcpy(&samples[aatx][write_start_idx], tx_ant_buffer_in, (write_end_idx - write_start_idx) * sizeof(c16_t));
} else {
for (int s = write_start_idx; s < write_end_idx; s++) {
samples[aatx][s].r = tx_ant_buffer_in->r * gain_linear;
samples[aatx][s].i = tx_ant_buffer_in->i * gain_linear;
tx_ant_buffer_in++;
}
}
} else {
// For subsequent beams, we need to ensure we accumulate the samples
if (gain_dB == 0.0f) {
for (int s = write_start_idx; s < write_end_idx; s++) {
samples[aatx][s].r += tx_ant_buffer_in->r;
samples[aatx][s].i += tx_ant_buffer_in->i;
tx_ant_buffer_in++;
}
} else {
for (int s = write_start_idx; s < write_end_idx; s++) {
samples[aatx][s].r += tx_ant_buffer_in->r * gain_linear;
samples[aatx][s].i += tx_ant_buffer_in->i * gain_linear;
tx_ant_buffer_in++;
}
}
} }
} }
} }
packets_copy.pop(); packets_copy.pop();
} }
return ant_buffers;
} }
static bool flushInput(rfsimulator_state_t *t, int timeout, bool first_time) static bool flushInput(rfsimulator_state_t *t, int timeout, bool first_time)
@@ -1164,11 +1187,13 @@ static void rfsimulator_read_internal(rfsimulator_state_t *t,
openair0_timestamp timestamp, openair0_timestamp timestamp,
int nsamps, int nsamps,
int nbAnt, int nbAnt,
int rx_beam_id) int rx_beam_id,
bool is_first_beam)
{ {
cf_t temp_array[nbAnt][nsamps]; cf_t temp_array[nbAnt][nsamps];
bool channel_modelling = false; bool channel_modelling = false;
// Add all input nodes signal in the output buffer // Add all input nodes signal in the output buffer
bool is_first_peer = true;
for (int sock = 0; sock < MAX_FD_RFSIMU; sock++) { for (int sock = 0; sock < MAX_FD_RFSIMU; sock++) {
buffer_t *ptr = &t->buf[sock]; buffer_t *ptr = &t->buf[sock];
@@ -1188,38 +1213,52 @@ static void rfsimulator_read_internal(rfsimulator_state_t *t,
} }
const uint64_t channel_offset = ptr->channel_model->channel_offset; const uint64_t channel_offset = ptr->channel_model->channel_offset;
const uint64_t channel_length = ptr->channel_model->channel_length; const uint64_t channel_length = ptr->channel_model->channel_length;
std::vector<std::vector<c16_t>> ant_buffers = combine_received_beams(t, std::vector<std::vector<c16_t>> ant_buffers(ptr->nbAnt, std::vector<c16_t>(nsamps + channel_length - 1, {0, 0}));
ptr->received_packets, c16_t *input[ant_buffers.size()];
timestamp - channel_offset - (channel_length - 1),
ptr->nbAnt,
nsamps + channel_length - 1,
rx_beam_id);
const c16_t *input[ant_buffers.size()];
for (uint aatx = 0; aatx < ant_buffers.size(); aatx++) { for (uint aatx = 0; aatx < ant_buffers.size(); aatx++) {
input[aatx] = ant_buffers[aatx].data(); input[aatx] = ant_buffers[aatx].data();
} }
combine_received_beams(t,
ptr->received_packets,
timestamp - channel_offset - (channel_length - 1),
ptr->nbAnt,
nsamps + channel_length - 1,
rx_beam_id,
input);
for (int aarx = 0; aarx < nbAnt; aarx++) { for (int aarx = 0; aarx < nbAnt; aarx++) {
rxAddInput(input, temp_array[aarx], aarx, ptr->channel_model, nsamps, timestamp); rxAddInput(input, temp_array[aarx], aarx, ptr->channel_model, nsamps, timestamp);
} }
} else { } else {
std::vector<std::vector<c16_t>> ant_buffers = if (is_first_beam && is_first_peer && (ptr->nbAnt == 1 || nbAnt == 1)) {
combine_received_beams(t, ptr->received_packets, timestamp, ptr->nbAnt, nsamps, rx_beam_id); // optimization: The buffer is uninitialized so samples can be written directly in the buffer
for (int aarx = 0; aarx < nbAnt; aarx++) { combine_received_beams(t, ptr->received_packets, timestamp, 1, nsamps, rx_beam_id, samples);
double H_awgn_mimo_coeff[ant_buffers.size()]; } else {
for (int aatx = 0; aatx < (int)ant_buffers.size(); aatx++) { std::vector<std::vector<c16_t>> ant_buffers(ptr->nbAnt, std::vector<c16_t>(nsamps, {0, 0}));
uint32_t ant_diff = std::abs(aatx - aarx); c16_t *input[ant_buffers.size()];
H_awgn_mimo_coeff[aatx] = ant_diff ? (0.2 / ant_diff) : 1.0; for (uint aatx = 0; aatx < ant_buffers.size(); aatx++) {
input[aatx] = ant_buffers[aatx].data();
} }
combine_received_beams(t, ptr->received_packets, timestamp, ptr->nbAnt, nsamps, rx_beam_id, input);
for (int aarx = 0; aarx < nbAnt; aarx++) {
double H_awgn_mimo_coeff[ant_buffers.size()];
for (int aatx = 0; aatx < (int)ant_buffers.size(); aatx++) {
uint32_t ant_diff = std::abs(aatx - aarx);
H_awgn_mimo_coeff[aatx] = ant_diff ? (0.2 / ant_diff) : 1.0;
}
for (uint aatx = 0; aatx < ant_buffers.size(); aatx++) { // sum up signals from nbAnt_tx antennas for (uint aatx = 0; aatx < ant_buffers.size(); aatx++) {
for (int i = 0; i < nsamps; i++) { // loop over nsamps for (int i = 0; i < nsamps; i++) {
samples[aarx][i].r += ant_buffers[aatx][i].r * H_awgn_mimo_coeff[aatx]; samples[aarx][i].r += ant_buffers[aatx][i].r * H_awgn_mimo_coeff[aatx];
samples[aarx][i].i += ant_buffers[aatx][i].i * H_awgn_mimo_coeff[aatx]; samples[aarx][i].i += ant_buffers[aatx][i].i * H_awgn_mimo_coeff[aatx];
} // end for a_tx }
} // end for i (number of samps) }
} // end for a_rx }
}
} }
} }
is_first_peer = false;
} }
bool apply_global_noise = get_noise_power_dBFS() != INVALID_DBFS_VALUE; bool apply_global_noise = get_noise_power_dBFS() != INVALID_DBFS_VALUE;
@@ -1347,7 +1386,7 @@ static int rfsimulator_read_beams(openair0_device *device,
for (int i = 0; i < nbAnt; i++) { for (int i = 0; i < nbAnt; i++) {
samples_beam[i] = (c16_t *)samplesVoid[beam][i] + timestamp - t->nextRxTstamp; samples_beam[i] = (c16_t *)samplesVoid[beam][i] + timestamp - t->nextRxTstamp;
} }
rfsimulator_read_internal(t, samples_beam, timestamp, nsamps_beam_map, nbAnt, rx_beam_ids[beam]); rfsimulator_read_internal(t, samples_beam, timestamp, nsamps_beam_map, nbAnt, rx_beam_ids[beam], beam == 0);
} }
timestamp += nsamps_beam_map; timestamp += nsamps_beam_map;
nsamps_to_process -= nsamps_beam_map; nsamps_to_process -= nsamps_beam_map;