FERS 1.0.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
radar_signal.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2//
3// Copyright (c) 2006-2008 Marc Brooker and Michael Inggs
4// Copyright (c) 2008-present FERS Contributors (see AUTHORS.md).
5//
6// See the GNU GPLv2 LICENSE file in the FERS project root for more information.
7
8/**
9 * @file radar_signal.cpp
10 * @brief Classes for handling radar waveforms and signals.
11 */
12
13#include "radar_signal.h"
14
15#include <algorithm>
16#include <cmath>
17#include <complex>
18#include <iterator>
19#include <stdexcept>
20#include <utility>
21
22#include "core/parameters.h"
23#include "dsp_filters.h"
26
27namespace fers_signal
28{
29 std::vector<ComplexType> CwSignal::render(const std::vector<interp::InterpPoint>& /*points*/, unsigned& size,
30 const RealType /*fracWinDelay*/) const
31 {
32 size = 0;
33 return {};
34 }
35
36 RadarSignal::RadarSignal(std::string name, const RealType power, const RealType carrierfreq, const RealType length,
37 std::unique_ptr<Signal> signal, const SimId id) :
38 _name(std::move(name)), _id(id == 0 ? SimIdGenerator::instance().generateId(ObjectType::Waveform) : id),
39 _power(power), _carrierfreq(carrierfreq), _length(length), _signal(std::move(signal))
40 {
41 if (!_signal)
42 {
43 throw std::runtime_error("Signal is empty");
44 }
45 }
46
47 std::vector<ComplexType> RadarSignal::render(const std::vector<interp::InterpPoint>& points, unsigned& size,
48 const RealType fracWinDelay) const
49 {
50 auto data = _signal->render(points, size, fracWinDelay);
51 const RealType scale = std::sqrt(_power);
52
53 std::ranges::for_each(data, [scale](auto& value) { value *= scale; });
54
55 return data;
56 }
57
58 void Signal::clear() noexcept
59 {
60 _size = 0;
61 _rate = 0;
62 }
63
64 void Signal::load(std::span<const ComplexType> inData, const unsigned samples, const RealType sampleRate)
65 {
66 clear();
67 const unsigned ratio = params::oversampleRatio();
68 _data.resize(samples * ratio);
69 _size = samples * ratio;
70 _rate = sampleRate * ratio;
71
72 if (ratio == 1)
73 {
74 std::ranges::copy(inData, _data.begin());
75 }
76 else
77 {
78 upsample(inData, samples, _data);
79 }
80 }
81
82 std::vector<ComplexType> Signal::render(const std::vector<interp::InterpPoint>& points, unsigned& size,
83 const double fracWinDelay) const
84 {
85 auto out = std::vector<ComplexType>(_size);
86 size = _size;
87
88 const RealType timestep = 1.0 / _rate;
89 const int filt_length = static_cast<int>(params::renderFilterLength());
91
92 auto iter = points.begin();
93 auto next = points.size() > 1 ? std::next(iter) : iter;
94 const RealType idelay = std::round(_rate * iter->delay);
95 RealType sample_time = iter->time;
96
97 for (int i = 0; i < static_cast<int>(_size); ++i)
98 {
99 if (sample_time > next->time && next != iter)
100 {
101 iter = next;
102 if (std::next(next) != points.end())
103 {
104 ++next;
105 }
106 }
107
108 auto [amplitude, phase, fdelay, i_sample_unwrap] =
109 calculateWeightsAndDelays(iter, next, sample_time, idelay, fracWinDelay);
110 const auto& filt = interp.getFilter(fdelay);
111 ComplexType accum = performConvolution(i, filt.data(), filt_length, amplitude, i_sample_unwrap);
112 out[static_cast<std::size_t>(i)] = std::exp(ComplexType(0.0, 1.0) * phase) * accum;
113
114 sample_time += timestep;
115 }
116
117 return out;
118 }
119
120 std::tuple<RealType, RealType, RealType, int>
121 Signal::calculateWeightsAndDelays(const std::vector<interp::InterpPoint>::const_iterator iter,
122 const std::vector<interp::InterpPoint>::const_iterator next,
123 const RealType sampleTime, const RealType idelay,
124 const RealType fracWinDelay) const noexcept
125 {
126 const RealType bw = iter < next ? (sampleTime - iter->time) / (next->time - iter->time) : 0.0;
127
128 const RealType amplitude = std::lerp(std::sqrt(iter->power), std::sqrt(next->power), bw);
129 const RealType phase = std::lerp(iter->phase, next->phase, bw);
130 RealType fdelay = -(std::lerp(iter->delay, next->delay, bw) * _rate - idelay + fracWinDelay);
131
132 const int i_sample_unwrap = static_cast<int>(std::floor(fdelay));
133 fdelay -= i_sample_unwrap;
134
135 return {amplitude, phase, fdelay, i_sample_unwrap};
136 }
137
138 ComplexType Signal::performConvolution(const int i, const RealType* filt, const int filtLength,
139 const RealType amplitude, const int iSampleUnwrap) const noexcept
140 {
141 const int start = std::max(-filtLength / 2, -i);
142 const int end = std::min(filtLength / 2, static_cast<int>(_size) - i);
143
144 ComplexType accum(0.0, 0.0);
145
146 for (int j = start; j < end; ++j)
147 {
148 const int sample_idx = i + j + iSampleUnwrap;
149 const int filt_idx = j + filtLength / 2;
150 if (sample_idx >= 0 && sample_idx < static_cast<int>(_size) && filt_idx >= 0 && filt_idx < filtLength)
151 {
152 accum += amplitude * _data[static_cast<std::size_t>(sample_idx)] * filt[filt_idx];
153 }
154 }
155
156 return accum;
157 }
158}
Thread-safe Meyers singleton for generating unique object IDs.
Definition sim_id.h:42
std::vector< ComplexType > render(const std::vector< interp::InterpPoint > &points, unsigned &size, RealType fracWinDelay) const override
Renders the signal data.
RadarSignal(std::string name, RealType power, RealType carrierfreq, RealType length, std::unique_ptr< Signal > signal, const SimId id=0)
Constructs a RadarSignal object.
std::vector< ComplexType > render(const std::vector< interp::InterpPoint > &points, unsigned &size, RealType fracWinDelay) const
Renders the radar signal.
void clear() noexcept
Clears the internal signal data.
void load(std::span< const ComplexType > inData, unsigned samples, RealType sampleRate)
Loads complex radar waveform data.
virtual std::vector< ComplexType > render(const std::vector< interp::InterpPoint > &points, unsigned &size, double fracWinDelay) const
Renders the signal data based on interpolation points.
static InterpFilter & getInstance() noexcept
Retrieves the singleton instance of the InterpFilter class.
double RealType
Type for real numbers.
Definition config.h:27
std::complex< RealType > ComplexType
Type for complex numbers.
Definition config.h:35
Header file for Digital Signal Processing (DSP) filters and upsampling/downsampling functionality.
Interpolation filter implementation using Kaiser windowing.
Defines a structure to store interpolation point data for signal processing.
void upsample(const std::span< const ComplexType > in, const unsigned size, std::span< ComplexType > out)
Upsamples a signal by a given ratio.
unsigned oversampleRatio() noexcept
Get the oversampling ratio.
Definition parameters.h:151
unsigned renderFilterLength() noexcept
Get the render filter length.
Definition parameters.h:139
Defines the Parameters struct and provides methods for managing simulation parameters.
Classes for handling radar waveforms and signals.
uint64_t SimId
64-bit Unique Simulation ID.
Definition sim_id.h:18
ObjectType
Categorizes objects for ID generation.
Definition sim_id.h:25