FERS 0.1.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
fers_signal::FmcwChirpSignal Class Referencefinal

FMCW linear chirp signal implementation. More...

#include "radar_signal.h"

+ Inheritance diagram for fers_signal::FmcwChirpSignal:
+ Collaboration diagram for fers_signal::FmcwChirpSignal:

Public Member Functions

 FmcwChirpSignal (RealType chirp_bandwidth, RealType chirp_duration, RealType chirp_period, RealType start_frequency_offset=0.0, std::optional< std::size_t > chirp_count=std::nullopt, FmcwChirpDirection direction=FmcwChirpDirection::Up)
 Constructs an FMCW chirp signal with timing and sweep parameters.
 
 ~FmcwChirpSignal () override=default
 
 FmcwChirpSignal (const FmcwChirpSignal &) noexcept=delete
 
FmcwChirpSignaloperator= (const FmcwChirpSignal &) noexcept=delete
 
 FmcwChirpSignal (FmcwChirpSignal &&) noexcept=delete
 
FmcwChirpSignaloperator= (FmcwChirpSignal &&) noexcept=delete
 
RealType getChirpBandwidth () const noexcept
 Gets the chirp bandwidth in hertz.
 
RealType getChirpDuration () const noexcept
 Gets the chirp duration in seconds.
 
RealType getChirpPeriod () const noexcept
 Gets the chirp period in seconds.
 
RealType getStartFrequencyOffset () const noexcept
 Gets the start frequency offset relative to carrier in hertz.
 
const std::optional< std::size_t > & getChirpCount () const noexcept
 Gets the optional finite chirp count.
 
RealType getChirpRate () const noexcept
 Gets the chirp rate in hertz per second.
 
RealType getSignedChirpRate () const noexcept
 Gets the signed chirp rate in hertz per second.
 
FmcwChirpDirection getDirection () const noexcept
 Gets the FMCW sweep direction.
 
bool isDownChirp () const noexcept
 Returns true when this chirp sweeps downward.
 
bool isTriangle () const noexcept
 Returns false for linear chirps; triangles override this shape predicate.
 
std::optional< std::size_t > activeChirpIndexAt (RealType time_since_segment_start) const noexcept
 Returns the active chirp index for a time since the segment start.
 
bool isActiveAt (RealType time_since_segment_start) const noexcept
 Returns true when the signal is inside an active chirp at the specified time.
 
RealType basebandPhaseForChirpTime (RealType chirp_time) const noexcept
 Computes baseband phase for a time inside a chirp.
 
std::optional< RealTypeinstantaneousBasebandPhase (RealType time_since_segment_start) const noexcept
 Computes instantaneous baseband phase at a time since segment start.
 
std::vector< ComplexTyperender (const std::vector< interp::InterpPoint > &points, unsigned &size, RealType fracWinDelay) const override
 Renders an FMCW waveform from interpolation points.
 
bool isFmcwFamily () const noexcept override
 Returns true when this signal belongs to the FMCW waveform family.
 
void clear () noexcept
 Clears the internal signal data.
 
void load (std::span< const ComplexType > inData, unsigned samples, RealType sampleRate)
 Loads complex radar waveform data.
 
RealType getRate () const noexcept
 Gets the sample rate of the signal.
 
unsigned getSampleCount () const noexcept
 Gets the number of native samples held by this signal.
 
virtual std::vector< ComplexTyperenderSlice (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.
 

Detailed Description

FMCW linear chirp signal implementation.

Definition at line 399 of file radar_signal.h.

Constructor & Destructor Documentation

◆ FmcwChirpSignal() [1/3]

fers_signal::FmcwChirpSignal::FmcwChirpSignal ( RealType  chirp_bandwidth,
RealType  chirp_duration,
RealType  chirp_period,
RealType  start_frequency_offset = 0.0,
std::optional< std::size_t >  chirp_count = std::nullopt,
FmcwChirpDirection  direction = FmcwChirpDirection::Up 
)

Constructs an FMCW chirp signal with timing and sweep parameters.

Definition at line 147 of file radar_signal.cpp.

149 :
150 _chirp_bandwidth(chirp_bandwidth), _chirp_duration(chirp_duration), _chirp_period(chirp_period),
151 _start_frequency_offset(start_frequency_offset), _chirp_count(chirp_count),
152 _chirp_rate(chirp_bandwidth / chirp_duration), _direction(direction)
153 {
154 }
math::Vec3 max

◆ ~FmcwChirpSignal()

fers_signal::FmcwChirpSignal::~FmcwChirpSignal ( )
overridedefault

◆ FmcwChirpSignal() [2/3]

fers_signal::FmcwChirpSignal::FmcwChirpSignal ( const FmcwChirpSignal )
deletenoexcept

◆ FmcwChirpSignal() [3/3]

fers_signal::FmcwChirpSignal::FmcwChirpSignal ( FmcwChirpSignal &&  )
deletenoexcept

Member Function Documentation

◆ activeChirpIndexAt()

std::optional< std::size_t > fers_signal::FmcwChirpSignal::activeChirpIndexAt ( RealType  time_since_segment_start) const
noexcept

Returns the active chirp index for a time since the segment start.

Definition at line 157 of file radar_signal.cpp.

158 {
159 if (time_since_segment_start < 0.0)
160 {
161 return std::nullopt;
162 }
163
164 const auto chirp_index = static_cast<std::size_t>(std::floor(time_since_segment_start / _chirp_period));
165 if (_chirp_count.has_value() && chirp_index >= *_chirp_count)
166 {
167 return std::nullopt;
168 }
169
170 const RealType chirp_time = time_since_segment_start - static_cast<RealType>(chirp_index) * _chirp_period;
171 // Exact arithmetic cannot make this negative, but floating-point boundary rounding can.
172 if (chirp_time < 0.0 || chirp_time >= _chirp_duration)
173 {
174 return std::nullopt;
175 }
176
177 return chirp_index;
178 }
double RealType
Type for real numbers.
Definition config.h:27

References max.

◆ basebandPhaseForChirpTime()

RealType fers_signal::FmcwChirpSignal::basebandPhaseForChirpTime ( RealType  chirp_time) const
noexcept

Computes baseband phase for a time inside a chirp.

Definition at line 193 of file radar_signal.cpp.

194 {
195 return 2.0 * PI * _start_frequency_offset * chirp_time + PI * getSignedChirpRate() * chirp_time * chirp_time;
196 }
RealType getSignedChirpRate() const noexcept
Gets the signed chirp rate in hertz per second.
constexpr RealType PI
Mathematical constant π (pi).
Definition config.h:43

References max, and PI.

◆ clear()

void fers_signal::Signal::clear ( )
noexceptinherited

Clears the internal signal data.

Definition at line 334 of file radar_signal.cpp.

335 {
336 _size = 0;
337 _rate = 0;
338 }

Referenced by fers_signal::Signal::load().

+ Here is the caller graph for this function:

◆ getChirpBandwidth()

RealType fers_signal::FmcwChirpSignal::getChirpBandwidth ( ) const
noexcept

Gets the chirp bandwidth in hertz.

Definition at line 418 of file radar_signal.h.

418{ return _chirp_bandwidth; }

◆ getChirpCount()

const std::optional< std::size_t > & fers_signal::FmcwChirpSignal::getChirpCount ( ) const
noexcept

Gets the optional finite chirp count.

Definition at line 430 of file radar_signal.h.

430{ return _chirp_count; }

◆ getChirpDuration()

RealType fers_signal::FmcwChirpSignal::getChirpDuration ( ) const
noexcept

Gets the chirp duration in seconds.

Definition at line 421 of file radar_signal.h.

421{ return _chirp_duration; }

Referenced by serial::fmcw_validation::validateSchedule().

+ Here is the caller graph for this function:

◆ getChirpPeriod()

RealType fers_signal::FmcwChirpSignal::getChirpPeriod ( ) const
noexcept

Gets the chirp period in seconds.

Definition at line 424 of file radar_signal.h.

424{ return _chirp_period; }

Referenced by serial::fmcw_validation::validateSchedule().

+ Here is the caller graph for this function:

◆ getChirpRate()

RealType fers_signal::FmcwChirpSignal::getChirpRate ( ) const
noexcept

Gets the chirp rate in hertz per second.

Definition at line 433 of file radar_signal.h.

433{ return _chirp_rate; }

◆ getDirection()

FmcwChirpDirection fers_signal::FmcwChirpSignal::getDirection ( ) const
noexcept

Gets the FMCW sweep direction.

Definition at line 442 of file radar_signal.h.

442{ return _direction; }

◆ getRate()

RealType fers_signal::Signal::getRate ( ) const
noexceptinherited

Gets the sample rate of the signal.

Returns
The sample rate of the signal.

Definition at line 86 of file radar_signal.h.

86{ return _rate; }

◆ getSampleCount()

unsigned fers_signal::Signal::getSampleCount ( ) const
noexceptinherited

Gets the number of native samples held by this signal.

Definition at line 89 of file radar_signal.h.

89{ return _size; }

◆ getSignedChirpRate()

RealType fers_signal::FmcwChirpSignal::getSignedChirpRate ( ) const
noexcept

Gets the signed chirp rate in hertz per second.

Definition at line 436 of file radar_signal.h.

437 {
438 return isDownChirp() ? -_chirp_rate : _chirp_rate;
439 }
bool isDownChirp() const noexcept
Returns true when this chirp sweeps downward.

◆ getStartFrequencyOffset()

RealType fers_signal::FmcwChirpSignal::getStartFrequencyOffset ( ) const
noexcept

Gets the start frequency offset relative to carrier in hertz.

Definition at line 427 of file radar_signal.h.

427{ return _start_frequency_offset; }

◆ instantaneousBasebandPhase()

std::optional< RealType > fers_signal::FmcwChirpSignal::instantaneousBasebandPhase ( RealType  time_since_segment_start) const
noexcept

Computes instantaneous baseband phase at a time since segment start.

Definition at line 181 of file radar_signal.cpp.

182 {
184 if (!chirp_index.has_value())
185 {
186 return std::nullopt;
187 }
188
189 const RealType chirp_time = time_since_segment_start - static_cast<RealType>(*chirp_index) * _chirp_period;
191 }
RealType basebandPhaseForChirpTime(RealType chirp_time) const noexcept
Computes baseband phase for a time inside a chirp.
std::optional< std::size_t > activeChirpIndexAt(RealType time_since_segment_start) const noexcept
Returns the active chirp index for a time since the segment start.

References max.

◆ isActiveAt()

bool fers_signal::FmcwChirpSignal::isActiveAt ( RealType  time_since_segment_start) const
noexcept

Returns true when the signal is inside an active chirp at the specified time.

Definition at line 454 of file radar_signal.h.

455 {
457 }

References max.

◆ isDownChirp()

bool fers_signal::FmcwChirpSignal::isDownChirp ( ) const
noexcept

Returns true when this chirp sweeps downward.

Definition at line 445 of file radar_signal.h.

445{ return _direction == FmcwChirpDirection::Down; }
@ Down
Instantaneous baseband frequency decreases over the chirp.

◆ isFmcwFamily()

bool fers_signal::FmcwChirpSignal::isFmcwFamily ( ) const
overridevirtualnoexcept

Returns true when this signal belongs to the FMCW waveform family.

Reimplemented from fers_signal::Signal.

Definition at line 470 of file radar_signal.h.

470{ return true; }

◆ isTriangle()

bool fers_signal::FmcwChirpSignal::isTriangle ( ) const
noexcept

Returns false for linear chirps; triangles override this shape predicate.

Definition at line 448 of file radar_signal.h.

448{ return false; }

◆ load()

void fers_signal::Signal::load ( std::span< const ComplexType inData,
unsigned  samples,
RealType  sampleRate 
)
inherited

Loads complex radar waveform data.

Parameters
inDataThe input span of complex signal data.
samplesThe number of samples in the input data.
sampleRateThe sample rate of the input data.

Definition at line 340 of file radar_signal.cpp.

341 {
342 clear();
343 const unsigned ratio = params::oversampleRatio();
344 const auto oversampled_samples = static_cast<std::size_t>(samples) * static_cast<std::size_t>(ratio);
345 if (oversampled_samples > std::numeric_limits<unsigned>::max())
346 {
347 throw std::overflow_error("Oversampled signal sample count exceeds unsigned range");
348 }
349 _data.resize(oversampled_samples);
350 _size = static_cast<unsigned>(oversampled_samples);
351 _rate = sampleRate * static_cast<RealType>(ratio);
352
353 if (ratio == 1)
354 {
355 std::ranges::copy(inData, _data.begin());
356 }
357 else
358 {
359 upsample(inData, samples, _data);
360 }
361 }
void clear() noexcept
Clears the internal signal data.
void upsample(const std::span< const ComplexType > in, const unsigned size, std::span< ComplexType > out)
Upsamples a complex waveform with zero-stuffing followed by Blackman FIR filtering.
unsigned oversampleRatio() noexcept
Get the oversampling ratio.
Definition parameters.h:151

References fers_signal::Signal::clear(), max, params::oversampleRatio(), and fers_signal::upsample().

+ Here is the call graph for this function:

◆ operator=() [1/2]

FmcwChirpSignal & fers_signal::FmcwChirpSignal::operator= ( const FmcwChirpSignal )
deletenoexcept

◆ operator=() [2/2]

FmcwChirpSignal & fers_signal::FmcwChirpSignal::operator= ( FmcwChirpSignal &&  )
deletenoexcept

◆ render()

std::vector< ComplexType > fers_signal::FmcwChirpSignal::render ( const std::vector< interp::InterpPoint > &  points,
unsigned size,
RealType  fracWinDelay 
) const
overridevirtual

Renders an FMCW waveform from interpolation points.

Reimplemented from fers_signal::Signal.

Definition at line 198 of file radar_signal.cpp.

200 {
201 size = 0;
202 return {};
203 }

References max.

◆ renderSlice()

std::vector< ComplexType > fers_signal::Signal::renderSlice ( const std::vector< interp::InterpPoint > &  points,
RealType  outputStartTime,
RealType  outputSampleRate,
std::size_t  sampleCount,
RealType  fracWinDelay 
) const
virtualinherited

Renders a bounded absolute-time slice on the requested output grid.

Definition at line 374 of file radar_signal.cpp.

377 {
378 auto out = std::vector<ComplexType>(sampleCount);
379 if (_size == 0 || _rate <= 0.0 || outputSampleRate <= 0.0 || points.empty())
380 {
381 return out;
382 }
383
384 const RealType timestep = 1.0 / outputSampleRate;
385 const int filt_length = static_cast<int>(params::renderFilterLength());
387
388 auto iter = points.begin();
389 auto next = points.size() > 1 ? std::next(iter) : iter;
390 const RealType idelay = std::round(_rate * iter->delay);
392
393 for (std::size_t i = 0; i < sampleCount; ++i)
394 {
395 while (sample_time > next->time && next != iter)
396 {
397 iter = next;
398 if (std::next(next) != points.end())
399 {
400 ++next;
401 }
402 else
403 {
404 break;
405 }
406 }
407
408 auto [amplitude, phase, fdelay, i_sample_unwrap] =
409 calculateWeightsAndDelays(iter, next, sample_time, idelay, fracWinDelay);
410 const RealType native_position = (sample_time - points.front().time) * _rate;
411 const auto source_index = static_cast<int>(std::floor(native_position));
414 {
415 source_fraction = 0.0;
416 }
417
419 const auto delay_unwrap = static_cast<int>(std::floor(combined_delay));
420 fdelay = combined_delay - static_cast<RealType>(delay_unwrap);
422
423 const auto& filt = interp.getFilter(fdelay);
424 const ComplexType accum =
425 performConvolution(source_index, filt.data(), filt_length, amplitude, i_sample_unwrap);
426 out[i] = std::exp(ComplexType(0.0, 1.0) * phase) * accum;
427
429 }
430
431 return out;
432 }
static InterpFilter & getInstance() noexcept
Retrieves the singleton instance of the InterpFilter class.
std::complex< RealType > ComplexType
Type for complex numbers.
Definition config.h:35
unsigned renderFilterLength() noexcept
Get the render filter length.
Definition parameters.h:139

References interp::InterpFilter::getInstance(), max, and params::renderFilterLength().

Referenced by fers_signal::Signal::render().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

The documentation for this class was generated from the following files: