FERS 0.1.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
radar_signal.h
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.h
10 * @brief Classes for handling radar waveforms and signals.
11 */
12
13#pragma once
14
15#include <cstddef>
16#include <cstdint>
17#include <memory>
18#include <optional>
19#include <span>
20#include <string>
21#include <string_view>
22#include <tuple>
23#include <vector>
24
25#include "core/config.h"
26#include "core/sim_id.h"
27
28namespace interp
29{
30 struct InterpPoint;
31}
32
33namespace fers_signal
34{
35 /// Sweep direction for a linear FMCW chirp.
36 enum class FmcwChirpDirection : std::uint8_t
37 {
38 Up, ///< Instantaneous baseband frequency increases over the chirp.
39 Down ///< Instantaneous baseband frequency decreases over the chirp.
40 };
41
42 /// Converts a chirp direction to the schema token.
44
45 /// Parses a schema chirp direction token.
47
48 /**
49 * @class Signal
50 * @brief Class for handling radar waveform signal data.
51 */
52 class Signal
53 {
54 public:
55 virtual ~Signal() = default;
56
57 Signal() = default;
58
59 Signal(const Signal&) = delete;
60
61 Signal& operator=(const Signal&) = delete;
62
63 Signal(Signal&&) = default;
64
65 Signal& operator=(Signal&&) = default;
66
67 /**
68 * @brief Clears the internal signal data.
69 */
70 void clear() noexcept;
71
72 /**
73 * @brief Loads complex radar waveform data.
74 *
75 * @param inData The input span of complex signal data.
76 * @param samples The number of samples in the input data.
77 * @param sampleRate The sample rate of the input data.
78 */
79 void load(std::span<const ComplexType> inData, unsigned samples, RealType sampleRate);
80
81 /**
82 * @brief Gets the sample rate of the signal.
83 *
84 * @return The sample rate of the signal.
85 */
86 [[nodiscard]] RealType getRate() const noexcept { return _rate; }
87
88 /// Gets the number of native samples held by this signal.
89 [[nodiscard]] unsigned getSampleCount() const noexcept { return _size; }
90
91 /**
92 * @brief Renders the signal data based on interpolation points.
93 *
94 * @param points A vector of interpolation points used to render the signal.
95 * @param size Reference to store the size of the rendered data.
96 * @param fracWinDelay Fractional window delay to apply during rendering.
97 * @return A vector of rendered complex signal data.
98 */
99 virtual std::vector<ComplexType> render(const std::vector<interp::InterpPoint>& points, unsigned& size,
100 double fracWinDelay) const;
101
102 /// Renders a bounded absolute-time slice on the requested output grid.
103 [[nodiscard]] virtual std::vector<ComplexType> renderSlice(const std::vector<interp::InterpPoint>& points,
105 std::size_t sampleCount,
106 RealType fracWinDelay) const;
107
108 /// Returns true when this signal belongs to the FMCW waveform family.
109 [[nodiscard]] virtual bool isFmcwFamily() const noexcept { return false; }
110
111 private:
112 std::vector<ComplexType> _data; ///< The complex signal data.
113 unsigned _size{0}; ///< The size of the signal data.
114 RealType _rate{0}; ///< The sample rate of the signal.
115
116 /**
117 * @brief Calculates weights and delays for rendering.
118 *
119 * @param iter Iterator pointing to the current interpolation point.
120 * @param next Iterator pointing to the next interpolation point.
121 * @param sampleTime Current sample time.
122 * @param idelay Integer delay value.
123 * @param fracWinDelay Fractional window delay to apply.
124 * @return A tuple containing amplitude, phase, fractional delay, and sample unwrap index.
125 */
126 [[nodiscard]] std::tuple<double, double, double, int>
127 calculateWeightsAndDelays(std::vector<interp::InterpPoint>::const_iterator iter,
128 std::vector<interp::InterpPoint>::const_iterator next, double sampleTime,
129 double idelay, double fracWinDelay) const noexcept;
130
131 /**
132 * @brief Performs convolution with a filter.
133 *
134 * @param i Index of the current sample.
135 * @param filt Pointer to the filter coefficients.
136 * @param filtLength Length of the filter.
137 * @param amplitude Amplitude scaling factor.
138 * @param iSampleUnwrap Unwrapped sample index for the convolution.
139 * @return The result of the convolution for the given sample.
140 */
141 ComplexType performConvolution(int i, const double* filt, int filtLength, double amplitude,
142 int iSampleUnwrap) const noexcept;
143 };
144
145 /**
146 * @class RadarSignal
147 * @brief Class representing a radar signal with associated properties.
148 */
150 {
151 public:
152 /**
153 * @brief Constructs a RadarSignal object.
154 *
155 * @param name The name of the radar signal.
156 * @param power The power of the radar signal.
157 * @param carrierfreq The carrier frequency of the radar signal.
158 * @param length The length of the radar signal.
159 * @param signal A unique pointer to the `Signal` object containing the waveform data.
160 * @throws std::runtime_error if the signal is null.
161 */
162 RadarSignal(std::string name, RealType power, RealType carrierfreq, RealType length,
163 std::unique_ptr<Signal> signal, const SimId id = 0);
164
165 ~RadarSignal() = default;
166
167 RadarSignal(const RadarSignal&) noexcept = delete;
168
169 RadarSignal& operator=(const RadarSignal&) noexcept = delete;
170
172
174
175 /**
176 * @brief Sets the filename associated with this signal.
177 * @param filename The source filename.
178 */
179 void setFilename(const std::string& filename) noexcept { _filename = filename; }
180
181 /**
182 * @brief Gets the filename associated with this signal.
183 * @return The source filename, if one was set.
184 */
185 [[nodiscard]] const std::optional<std::string>& getFilename() const noexcept { return _filename; }
186
187 /**
188 * @brief Gets the power of the radar signal.
189 *
190 * @return The power of the radar signal.
191 */
192 [[nodiscard]] RealType getPower() const noexcept { return _power; }
193
194 /**
195 * @brief Gets the carrier frequency of the radar signal.
196 *
197 * @return The carrier frequency of the radar signal.
198 */
199 [[nodiscard]] RealType getCarrier() const noexcept { return _carrierfreq; }
200
201 /**
202 * @brief Gets the name of the radar signal.
203 *
204 * @return The name of the radar signal.
205 */
206 [[nodiscard]] const std::string& getName() const noexcept { return _name; }
207
208 /**
209 * @brief Gets the unique ID of the radar signal.
210 *
211 * @return The radar signal SimId.
212 */
213 [[nodiscard]] SimId getId() const noexcept { return _id; }
214
215 /**
216 * @brief Gets the sample rate of the radar signal.
217 *
218 * @return The sample rate of the radar signal.
219 */
220 [[nodiscard]] RealType getRate() const noexcept { return _signal->getRate(); }
221
222 /// Gets the number of native samples in the underlying signal.
223 [[nodiscard]] unsigned getSampleCount() const noexcept { return _signal->getSampleCount(); }
224
225 /**
226 * @brief Gets the length of the radar signal.
227 *
228 * @return The length of the radar signal.
229 */
230 [[nodiscard]] RealType getLength() const noexcept { return _length; }
231
232 /**
233 * @brief Gets the underlying signal object.
234 * @return A const pointer to the Signal object.
235 */
236 [[nodiscard]] const Signal* getSignal() const noexcept { return _signal.get(); }
237
238 /// Returns true when this signal is a continuous-wave signal.
239 [[nodiscard]] bool isCw() const noexcept;
240
241 /// Returns true when this signal is an FMCW linear chirp signal.
243
244 /// Returns true when this signal is an FMCW triangular modulation signal.
246
247 /// Returns true when this signal belongs to the FMCW waveform family.
249
250 /// Gets the FMCW chirp implementation, if this signal owns one.
252
253 /// Gets the FMCW triangle implementation, if this signal owns one.
255
256 /**
257 * @brief Renders the radar signal.
258 *
259 * @param points A vector of interpolation points.
260 * @param size Reference to store the size of the rendered data.
261 * @param fracWinDelay Fractional window delay to apply during rendering.
262 * @return A vector of rendered complex radar signal data.
263 */
264 std::vector<ComplexType> render(const std::vector<interp::InterpPoint>& points, unsigned& size,
266
267 /// Renders a bounded absolute-time slice on the requested output grid.
268 [[nodiscard]] std::vector<ComplexType> renderSlice(const std::vector<interp::InterpPoint>& points,
270 std::size_t sampleCount, RealType fracWinDelay) const;
271
272 private:
273 std::string _name; ///< The name of the radar signal.
274 SimId _id; ///< Unique ID for this radar signal.
275 RealType _power; ///< The power of the radar signal.
276 RealType _carrierfreq; ///< The carrier frequency of the radar signal.
277 RealType _length; ///< The length of the radar signal.
278 std::unique_ptr<Signal> _signal; ///< The `Signal` object containing the radar signal data.
279 std::optional<std::string> _filename; ///< The original filename for file-based signals.
280 };
281
282 /// Continuous-wave signal implementation.
284 {
285 public:
286 CwSignal() = default;
287
288 ~CwSignal() override = default;
289
290 CwSignal(const CwSignal&) noexcept = delete;
291
292 CwSignal& operator=(const CwSignal&) noexcept = delete;
293
295
297
298 /**
299 * @brief Renders the signal data. For CW signals, this is a no-op.
300 * @return An empty vector of complex signal data.
301 */
302 std::vector<ComplexType> render(const std::vector<interp::InterpPoint>& points, unsigned& size,
304 };
305
306 /// FMCW linear chirp signal implementation.
308 {
309 public:
310 /// Constructs an FMCW chirp signal with timing and sweep parameters.
311 FmcwChirpSignal(RealType chirp_bandwidth, RealType chirp_duration, RealType chirp_period,
312 RealType start_frequency_offset = 0.0, std::optional<std::size_t> chirp_count = std::nullopt,
314
315 ~FmcwChirpSignal() override = default;
316
317 FmcwChirpSignal(const FmcwChirpSignal&) noexcept = delete;
318
319 FmcwChirpSignal& operator=(const FmcwChirpSignal&) noexcept = delete;
320
322
324
325 /// Gets the chirp bandwidth in hertz.
326 [[nodiscard]] RealType getChirpBandwidth() const noexcept { return _chirp_bandwidth; }
327
328 /// Gets the chirp duration in seconds.
329 [[nodiscard]] RealType getChirpDuration() const noexcept { return _chirp_duration; }
330
331 /// Gets the chirp period in seconds.
332 [[nodiscard]] RealType getChirpPeriod() const noexcept { return _chirp_period; }
333
334 /// Gets the start frequency offset relative to carrier in hertz.
335 [[nodiscard]] RealType getStartFrequencyOffset() const noexcept { return _start_frequency_offset; }
336
337 /// Gets the optional finite chirp count.
338 [[nodiscard]] const std::optional<std::size_t>& getChirpCount() const noexcept { return _chirp_count; }
339
340 /// Gets the chirp rate in hertz per second.
341 [[nodiscard]] RealType getChirpRate() const noexcept { return _chirp_rate; }
342
343 /// Gets the signed chirp rate in hertz per second.
345 {
346 return isDownChirp() ? -_chirp_rate : _chirp_rate;
347 }
348
349 /// Gets the FMCW sweep direction.
351
352 /// Returns true when this chirp sweeps downward.
353 [[nodiscard]] bool isDownChirp() const noexcept { return _direction == FmcwChirpDirection::Down; }
354
355 /// Returns false for linear chirps; triangles override this shape predicate.
356 [[nodiscard]] bool isTriangle() const noexcept { return false; }
357
358 /// Returns the active chirp index for a time since the segment start.
359 [[nodiscard]] std::optional<std::size_t> activeChirpIndexAt(RealType time_since_segment_start) const noexcept;
360
361 /// Returns true when the signal is inside an active chirp at the specified time.
363 {
364 return activeChirpIndexAt(time_since_segment_start).has_value();
365 }
366
367 /// Computes baseband phase for a time inside a chirp.
368 [[nodiscard]] RealType basebandPhaseForChirpTime(RealType chirp_time) const noexcept;
369
370 /// Computes instantaneous baseband phase at a time since segment start.
371 [[nodiscard]] std::optional<RealType>
372 instantaneousBasebandPhase(RealType time_since_segment_start) const noexcept;
373
374 /// Renders an FMCW waveform from interpolation points.
375 std::vector<ComplexType> render(const std::vector<interp::InterpPoint>& points, unsigned& size,
376 RealType fracWinDelay) const override;
377
378 [[nodiscard]] bool isFmcwFamily() const noexcept override { return true; }
379
380 private:
381 RealType _chirp_bandwidth{}; ///< Chirp bandwidth in hertz.
382 RealType _chirp_duration{}; ///< Active chirp duration in seconds.
383 RealType _chirp_period{}; ///< Chirp repetition period in seconds.
384 RealType _start_frequency_offset{}; ///< Start frequency offset relative to carrier in hertz.
385 std::optional<std::size_t> _chirp_count; ///< Optional finite chirp count.
386 RealType _chirp_rate{}; ///< Frequency sweep rate in hertz per second.
387 FmcwChirpDirection _direction{FmcwChirpDirection::Up}; ///< Frequency sweep direction.
388 };
389
390 /// FMCW symmetric triangular modulation signal implementation.
392 {
393 public:
394 /// Constructs an FMCW triangular modulation signal.
395 FmcwTriangleSignal(RealType chirp_bandwidth, RealType chirp_duration, RealType start_frequency_offset = 0.0,
396 std::optional<std::size_t> triangle_count = std::nullopt);
397
398 ~FmcwTriangleSignal() override = default;
399
400 FmcwTriangleSignal(const FmcwTriangleSignal&) noexcept = delete;
401
403
405
407
408 /// Gets the chirp bandwidth in hertz.
409 [[nodiscard]] RealType getChirpBandwidth() const noexcept { return _chirp_bandwidth; }
410
411 /// Gets the per-leg chirp duration in seconds.
412 [[nodiscard]] RealType getChirpDuration() const noexcept { return _chirp_duration; }
413
414 /// Gets the start frequency offset relative to carrier in hertz.
415 [[nodiscard]] RealType getStartFrequencyOffset() const noexcept { return _start_frequency_offset; }
416
417 /// Gets the optional finite triangle count.
418 [[nodiscard]] const std::optional<std::size_t>& getTriangleCount() const noexcept { return _triangle_count; }
419
420 /// Gets the chirp rate magnitude in hertz per second.
421 [[nodiscard]] RealType getChirpRate() const noexcept { return _chirp_rate; }
422
423 /// Gets the full up/down triangle period in seconds.
424 [[nodiscard]] RealType getTrianglePeriod() const noexcept { return _triangle_period; }
425
426 /// Gets the full, unreduced phase accumulated by one leg.
427 [[nodiscard]] RealType getDeltaPhiUp() const noexcept { return _delta_phi_up; }
428
429 /// Returns true for triangular FMCW waveforms.
430 [[nodiscard]] bool isTriangle() const noexcept { return true; }
431
432 /// Computes baseband phase at a time since the triangle train start.
433 [[nodiscard]] RealType basebandPhaseForTriangleTime(RealType triangle_time) const noexcept;
434
435 /// Computes instantaneous baseband phase at a time since segment start.
436 [[nodiscard]] std::optional<RealType>
437 instantaneousBasebandPhase(RealType time_since_segment_start) const noexcept;
438
439 /// Renders an FMCW waveform from interpolation points.
440 std::vector<ComplexType> render(const std::vector<interp::InterpPoint>& points, unsigned& size,
441 RealType fracWinDelay) const override;
442
443 [[nodiscard]] bool isFmcwFamily() const noexcept override { return true; }
444
445 private:
446 RealType _chirp_bandwidth{}; ///< Chirp bandwidth in hertz.
447 RealType _chirp_duration{}; ///< Per-leg chirp duration in seconds.
448 RealType _start_frequency_offset{}; ///< Start frequency offset relative to carrier in hertz.
449 std::optional<std::size_t> _triangle_count; ///< Optional finite triangle count.
450 RealType _chirp_rate{}; ///< Frequency sweep rate magnitude in hertz per second.
451 RealType _triangle_period{}; ///< Full triangle period in seconds.
452 RealType _delta_phi_up{}; ///< Full, unreduced phase accumulated by one leg.
453 };
454}
Continuous-wave signal implementation.
~CwSignal() override=default
CwSignal(CwSignal &&) noexcept=delete
CwSignal(const CwSignal &) noexcept=delete
CwSignal & operator=(const CwSignal &) noexcept=delete
FMCW linear chirp signal implementation.
bool isFmcwFamily() const noexcept override
Returns true when this signal belongs to the FMCW waveform family.
RealType getChirpDuration() const noexcept
Gets the chirp duration in seconds.
~FmcwChirpSignal() override=default
FmcwChirpSignal(FmcwChirpSignal &&) noexcept=delete
RealType getChirpPeriod() const noexcept
Gets the chirp period in seconds.
bool isTriangle() const noexcept
Returns false for linear chirps; triangles override this shape predicate.
FmcwChirpSignal & operator=(const FmcwChirpSignal &) noexcept=delete
FmcwChirpSignal(const FmcwChirpSignal &) noexcept=delete
bool isDownChirp() const noexcept
Returns true when this chirp sweeps downward.
FmcwChirpDirection getDirection() const noexcept
Gets the FMCW sweep direction.
const std::optional< std::size_t > & getChirpCount() const noexcept
Gets the optional finite chirp count.
RealType getSignedChirpRate() const noexcept
Gets the signed chirp rate in hertz per second.
RealType getChirpRate() const noexcept
Gets the chirp rate in hertz per second.
bool isActiveAt(RealType time_since_segment_start) const noexcept
Returns true when the signal is inside an active chirp at the specified time.
RealType getStartFrequencyOffset() const noexcept
Gets the start frequency offset relative to carrier in hertz.
FMCW symmetric triangular modulation signal implementation.
RealType getStartFrequencyOffset() const noexcept
Gets the start frequency offset relative to carrier in hertz.
RealType getChirpRate() const noexcept
Gets the chirp rate magnitude in hertz per second.
~FmcwTriangleSignal() override=default
const std::optional< std::size_t > & getTriangleCount() const noexcept
Gets the optional finite triangle count.
RealType getChirpDuration() const noexcept
Gets the per-leg chirp duration in seconds.
bool isFmcwFamily() const noexcept override
Returns true when this signal belongs to the FMCW waveform family.
RealType getTrianglePeriod() const noexcept
Gets the full up/down triangle period in seconds.
FmcwTriangleSignal(FmcwTriangleSignal &&) noexcept=delete
FmcwTriangleSignal(const FmcwTriangleSignal &) noexcept=delete
RealType getDeltaPhiUp() const noexcept
Gets the full, unreduced phase accumulated by one leg.
bool isTriangle() const noexcept
Returns true for triangular FMCW waveforms.
FmcwTriangleSignal & operator=(const FmcwTriangleSignal &) noexcept=delete
Class representing a radar signal with associated properties.
SimId getId() const noexcept
Gets the unique ID of the radar signal.
void setFilename(const std::string &filename) noexcept
Sets the filename associated with this signal.
RadarSignal(const RadarSignal &) noexcept=delete
RadarSignal & operator=(const RadarSignal &) noexcept=delete
const std::optional< std::string > & getFilename() const noexcept
Gets the filename associated with this signal.
std::vector< ComplexType > renderSlice(const std::vector< interp::InterpPoint > &points, RealType outputStartTime, RealType outputSampleRate, std::size_t sampleCount, RealType fracWinDelay) const
Renders a bounded absolute-time slice on the requested output grid.
RealType getRate() const noexcept
Gets the sample rate of the radar signal.
const class FmcwTriangleSignal * getFmcwTriangleSignal() const noexcept
Gets the FMCW triangle implementation, if this signal owns one.
std::vector< ComplexType > render(const std::vector< interp::InterpPoint > &points, unsigned &size, RealType fracWinDelay) const
Renders the radar signal.
RadarSignal(RadarSignal &&) noexcept=delete
const std::string & getName() const noexcept
Gets the name of the radar signal.
bool isFmcwTriangle() const noexcept
Returns true when this signal is an FMCW triangular modulation signal.
RealType getCarrier() const noexcept
Gets the carrier frequency of the radar signal.
bool isFmcwFamily() const noexcept
Returns true when this signal belongs to the FMCW waveform family.
RealType getLength() const noexcept
Gets the length of the radar signal.
const Signal * getSignal() const noexcept
Gets the underlying signal object.
bool isFmcwChirp() const noexcept
Returns true when this signal is an FMCW linear chirp signal.
bool isCw() const noexcept
Returns true when this signal is a continuous-wave signal.
const class FmcwChirpSignal * getFmcwChirpSignal() const noexcept
Gets the FMCW chirp implementation, if this signal owns one.
unsigned getSampleCount() const noexcept
Gets the number of native samples in the underlying signal.
RealType getPower() const noexcept
Gets the power of the radar signal.
Class for handling radar waveform signal data.
RealType getRate() const noexcept
Gets the sample rate of the signal.
virtual ~Signal()=default
Signal(Signal &&)=default
virtual std::vector< ComplexType > renderSlice(const std::vector< interp::InterpPoint > &points, RealType outputStartTime, RealType outputSampleRate, std::size_t sampleCount, RealType fracWinDelay) const
Renders a bounded absolute-time slice on the requested output grid.
void clear() noexcept
Clears the internal signal data.
Signal & operator=(const Signal &)=delete
Signal(const Signal &)=delete
unsigned getSampleCount() const noexcept
Gets the number of native samples held by this signal.
void load(std::span< const ComplexType > inData, unsigned samples, RealType sampleRate)
Loads complex radar waveform data.
virtual bool isFmcwFamily() const noexcept
Returns true when this signal belongs to the FMCW waveform family.
virtual std::vector< ComplexType > render(const std::vector< interp::InterpPoint > &points, unsigned &size, double fracWinDelay) const
Renders the signal data based on interpolation points.
Signal & operator=(Signal &&)=default
Global configuration file for the project.
double RealType
Type for real numbers.
Definition config.h:27
std::complex< RealType > ComplexType
Type for complex numbers.
Definition config.h:35
FmcwChirpDirection parseFmcwChirpDirection(const std::string_view direction)
Parses a schema chirp direction token.
std::string_view fmcwChirpDirectionToken(const FmcwChirpDirection direction) noexcept
Converts a chirp direction to the schema token.
FmcwChirpDirection
Sweep direction for a linear FMCW chirp.
@ Down
Instantaneous baseband frequency decreases over the chirp.
@ Up
Instantaneous baseband frequency increases over the chirp.
uint64_t SimId
64-bit Unique Simulation ID.
Definition sim_id.h:18
math::Vec3 max