38 void adcSimulate(std::span<ComplexType> data,
const unsigned bits,
const RealType fullscale)
noexcept
40 const RealType levels = std::pow(2, bits - 1);
42 for (
auto& sample : data)
44 auto [i, q] = std::tuple{std::clamp(std::floor(levels * sample.real() / fullscale) / levels, -1.0, 1.0),
45 std::clamp(std::floor(levels * sample.imag() / fullscale) / levels, -1.0, 1.0)};
60 const RealType start,
const RealType fracDelay,
const std::size_t localWindowSize)
64 const auto array = resp->
renderBinary(prate, psize, fracDelay);
65 int start_sample =
static_cast<int>(std::round(rate * (resp->
startTime() - start)));
66 const auto roffset = start_sample < 0 ? static_cast<std::size_t>(-start_sample) : std::size_t{0};
67 const auto start_offset =
static_cast<std::size_t
>(std::max(start_sample, 0));
69 for (std::size_t i = roffset; i < psize && i + start_offset < localWindowSize; ++i)
71 localWindow[i + start_offset] += array[i];
79 const RealType fracDelay,
const std::span<
const std::unique_ptr<serial::Response>> responses)
82 std::queue<serial::Response*> work_list;
84 for (
const auto& response : responses)
86 if (response->startTime() <= end && response->endTime() >= start)
88 work_list.push(response.get());
93 const auto local_window_size =
static_cast<std::size_t
>(std::ceil(length * rate));
95 std::vector local_window(local_window_size,
ComplexType{});
97 while (!work_list.empty())
99 const auto* resp = work_list.front();
101 processResponse(resp, local_window, rate, start, fracDelay, local_window_size);
104 for (std::size_t i = 0; i < local_window_size; ++i)
106 window[i] += local_window[i];
112 if (noiseTemperature == 0)
121 const RealType per_channel_power = total_power / 2.0;
122 const RealType stddev = std::sqrt(per_channel_power);
125 for (
auto& sample : window)
134 for (
const auto& sample : window)
136 const RealType real_abs = std::fabs(sample.real());
137 const RealType imag_abs = std::fabs(sample.imag());
139 max_value = std::max({max_value, real_abs, imag_abs});
144 adcSimulate(window, adc_bits, max_value);
146 else if (max_value != 0)
148 for (
auto& sample : window)
Generates white Gaussian noise.
RealType getSample() noexcept override
Generates a sample of white Gaussian noise.
Manages radar signal responses from a transmitter.
RealType startTime() const noexcept
Retrieves the start time of the response.
std::vector< ComplexType > renderBinary(RealType &rate, unsigned &size, RealType fracWinDelay) const
Renders the response in binary format.
double RealType
Type for real numbers.
std::complex< RealType > ComplexType
Type for complex numbers.
RealType rate() noexcept
Get the rendering sample rate.
RealType boltzmannK() noexcept
Get the Boltzmann constant.
unsigned oversampleRatio() noexcept
Get the oversampling ratio.
unsigned adcBits() noexcept
Get the ADC quantization bits.
void applyThermalNoise(std::span< ComplexType > window, const RealType noiseTemperature, std::mt19937 &rngEngine)
Applies thermal (Johnson-Nyquist) noise to a window of I/Q samples.
RealType quantizeAndScaleWindow(std::span< ComplexType > window)
Simulates ADC quantization and scales a window of complex I/Q samples.
void renderWindow(std::vector< ComplexType > &window, const RealType length, const RealType start, const RealType fracDelay, const std::span< const std::unique_ptr< serial::Response > > responses)
Renders a time-window of I/Q data from a collection of raw radar responses.
Header file for noise generator classes.
Defines the Parameters struct and provides methods for managing simulation parameters.
Classes for managing radar signal responses.
Header for receiver-side signal processing and rendering.
A simple thread pool implementation.