diff --git a/radio/rfsimulator/apply_channelmod.c b/radio/rfsimulator/apply_channelmod.c index 2dac26c4e6..3f2e8d85c1 100644 --- a/radio/rfsimulator/apply_channelmod.c +++ b/radio/rfsimulator/apply_channelmod.c @@ -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 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, int rxAnt, channel_desc_t *channelDesc, diff --git a/radio/rfsimulator/rfsimulator.h b/radio/rfsimulator/rfsimulator.h index 90c2be2f82..802a2a2e34 100644 --- a/radio/rfsimulator/rfsimulator.h +++ b/radio/rfsimulator/rfsimulator.h @@ -24,7 +24,7 @@ #ifndef __RFSIMULATOR_H #define __RFSIMULATOR_H #include -void rxAddInput(const c16_t **input_sig, +void rxAddInput(c16_t **input_sig, cf_t *after_channel_sig, int rxAnt, channel_desc_t *channelDesc, diff --git a/radio/rfsimulator/simulator.cpp b/radio/rfsimulator/simulator.cpp index 793dfedf18..b4b4b12ea2 100644 --- a/radio/rfsimulator/simulator.cpp +++ b/radio/rfsimulator/simulator.cpp @@ -1045,17 +1045,18 @@ static std::vector get_beam_ids(uint64_t beam_map) * @param num_aatx The number of antennas to process. * @param num_samples The number of samples to process. * @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. */ -static std::vector> combine_received_beams(rfsimulator_state_t *t, - std::queue &received_packets, - uint64_t start_timestamp, - int num_aatx, - size_t num_samples, - int rx_beam_id) +static void combine_received_beams(rfsimulator_state_t *t, + std::queue &received_packets, + uint64_t start_timestamp, + int num_aatx, + size_t num_samples, + int rx_beam_id, + c16_t **samples) { // Assume received_packets is ordered by timestamp - std::vector> ant_buffers(num_aatx, std::vector(num_samples, {0, 0})); std::queue packets_copy = received_packets; while (!packets_copy.empty()) { rfsim_packet_t *pkt = packets_copy.front(); @@ -1081,16 +1082,38 @@ static std::vector> combine_received_beams(rfsimulator_state_ for (int aatx = 0; aatx < num_aatx; aatx++) { c16_t *buffer = (c16_t *)pkt->payload; 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++) { - ant_buffers[aatx][s].r += tx_ant_buffer_in->r * gain_linear; - ant_buffers[aatx][s].i += tx_ant_buffer_in->i * gain_linear; - tx_ant_buffer_in++; + if (beam == 0) { + // For the first beam, we can directly copy the samples + if (gain_dB == 0.0f) { + // 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(); } - return ant_buffers; } 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, int nsamps, int nbAnt, - int rx_beam_id) + int rx_beam_id, + bool is_first_beam) { cf_t temp_array[nbAnt][nsamps]; bool channel_modelling = false; // Add all input nodes signal in the output buffer + bool is_first_peer = true; for (int sock = 0; sock < MAX_FD_RFSIMU; 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_length = ptr->channel_model->channel_length; - std::vector> ant_buffers = combine_received_beams(t, - ptr->received_packets, - timestamp - channel_offset - (channel_length - 1), - ptr->nbAnt, - nsamps + channel_length - 1, - rx_beam_id); - const c16_t *input[ant_buffers.size()]; + std::vector> ant_buffers(ptr->nbAnt, std::vector(nsamps + channel_length - 1, {0, 0})); + c16_t *input[ant_buffers.size()]; for (uint aatx = 0; aatx < ant_buffers.size(); aatx++) { 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++) { rxAddInput(input, temp_array[aarx], aarx, ptr->channel_model, nsamps, timestamp); } } else { - std::vector> ant_buffers = - combine_received_beams(t, ptr->received_packets, timestamp, ptr->nbAnt, nsamps, rx_beam_id); - 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; + if (is_first_beam && is_first_peer && (ptr->nbAnt == 1 || nbAnt == 1)) { + // optimization: The buffer is uninitialized so samples can be written directly in the buffer + combine_received_beams(t, ptr->received_packets, timestamp, 1, nsamps, rx_beam_id, samples); + } else { + std::vector> ant_buffers(ptr->nbAnt, std::vector(nsamps, {0, 0})); + c16_t *input[ant_buffers.size()]; + 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 (int i = 0; i < nsamps; i++) { // loop over nsamps - 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]; - } // end for a_tx - } // end for i (number of samps) - } // end for a_rx + for (uint aatx = 0; aatx < ant_buffers.size(); aatx++) { + for (int i = 0; i < nsamps; i++) { + 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]; + } + } + } + } } } + is_first_peer = false; } 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++) { 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; nsamps_to_process -= nsamps_beam_map;