Added two versions of channel convolution and noise generation: - accelerated via threadpool - accelerated using CUDA The main difference between this and previous versions of channel convolution implementations is that these functions take a real-world approach to input/output where both could be split unevenly over a set of buffers, e.g. ring buffers used in vrtsim. The CUDA-accelerated version only works on systems with unified memory, e.g. NVidia DGX Spark or GH
85 lines
2.4 KiB
C
85 lines
2.4 KiB
C
/*
|
|
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include "test_channel_pipeline_tools.h"
|
|
#include "channel_pipeline.h"
|
|
#include "thread-pool.h"
|
|
|
|
void *init_tpool(int num_threads)
|
|
{
|
|
tpool_t *tpool = malloc(sizeof(*tpool));
|
|
initFloatingCoresTpool(num_threads, tpool, false, NULL);
|
|
return tpool;
|
|
}
|
|
|
|
void destroy_tpool(void *tpool)
|
|
{
|
|
abortTpool((tpool_t *)tpool);
|
|
free(tpool);
|
|
}
|
|
|
|
void channel_convolution_cpu(const cf_t **channel,
|
|
const c16_t **tx_sig0,
|
|
const c16_t **tx_sig1,
|
|
int num_samples_tx_sig0,
|
|
c16_t **rx_sig0,
|
|
c16_t **rx_sig1,
|
|
int num_samples_rx_sig0,
|
|
int num_samples,
|
|
int channel_length,
|
|
int nb_tx,
|
|
int nb_rx)
|
|
{
|
|
for (int rx_ant = 0; rx_ant < nb_rx; rx_ant++) {
|
|
for (int i = 0; i < num_samples; i++) {
|
|
float rx_r = 0.0f;
|
|
float rx_i = 0.0f;
|
|
|
|
for (int tx_ant = 0; tx_ant < nb_tx; tx_ant++) {
|
|
for (int l = 0; l < channel_length; l++) {
|
|
int idx = i + (channel_length - 1) - l;
|
|
c16_t in_sample;
|
|
if (idx < num_samples_tx_sig0) {
|
|
in_sample = tx_sig0[tx_ant][idx];
|
|
} else {
|
|
in_sample = tx_sig1[tx_ant][idx - num_samples_tx_sig0];
|
|
}
|
|
cf_t tx_sample = {(float)in_sample.r, (float)in_sample.i};
|
|
|
|
int chan_idx = tx_ant + nb_tx * rx_ant;
|
|
cf_t ch = channel[chan_idx][l];
|
|
|
|
rx_r += tx_sample.r * ch.r - tx_sample.i * ch.i;
|
|
rx_i += tx_sample.r * ch.i + tx_sample.i * ch.r;
|
|
}
|
|
}
|
|
|
|
if (i < num_samples_rx_sig0) {
|
|
rx_sig0[rx_ant][i].r = (int16_t)rx_r;
|
|
rx_sig0[rx_ant][i].i = (int16_t)rx_i;
|
|
} else {
|
|
rx_sig1[rx_ant][i - num_samples_rx_sig0].r = (int16_t)rx_r;
|
|
rx_sig1[rx_ant][i - num_samples_rx_sig0].i = (int16_t)rx_i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void generate_random_signal(c16_t *sig, int num_samples)
|
|
{
|
|
for (int i = 0; i < num_samples; i++) {
|
|
sig[i].r = (rand() % 2000) - 1000;
|
|
sig[i].i = (rand() % 2000) - 1000;
|
|
}
|
|
}
|
|
|
|
void generate_random_signal_float(cf_t *sig, int num_samples)
|
|
{
|
|
for (int i = 0; i < num_samples; i++) {
|
|
sig[i].r = (rand() % 2000) - 1000;
|
|
sig[i].i = (rand() % 2000) - 1000;
|
|
}
|
|
}
|