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

Stepped-frequency continuous-wave signal implementation. More...

#include "radar_signal.h"

+ Inheritance diagram for fers_signal::SteppedFrequencySignal:
+ Collaboration diagram for fers_signal::SteppedFrequencySignal:

Classes

struct  StepState
 Active SFCW dwell selected for one local waveform time. More...
 

Public Member Functions

 SteppedFrequencySignal (RealType start_frequency_offset, RealType step_size, std::size_t step_count, RealType dwell_time, RealType step_period, std::optional< std::size_t > sweep_count=std::nullopt)
 Constructs a uniform stepped-frequency CW signal.
 
 ~SteppedFrequencySignal () override=default
 
 SteppedFrequencySignal (const SteppedFrequencySignal &) noexcept=delete
 
SteppedFrequencySignaloperator= (const SteppedFrequencySignal &) noexcept=delete
 
 SteppedFrequencySignal (SteppedFrequencySignal &&) noexcept=delete
 
SteppedFrequencySignaloperator= (SteppedFrequencySignal &&) noexcept=delete
 
RealType getStartFrequencyOffset () const noexcept
 Gets the first-step offset from carrier in hertz.
 
RealType getStepSize () const noexcept
 Gets the uniform frequency step in hertz.
 
std::size_t getStepCount () const noexcept
 Gets the number of steps per sweep.
 
RealType getDwellTime () const noexcept
 Gets active dwell time per step in seconds.
 
RealType getStepPeriod () const noexcept
 Gets step repetition period in seconds.
 
const std::optional< std::size_t > & getSweepCount () const noexcept
 Gets optional finite sweep count.
 
RealType getSweepPeriod () const noexcept
 Gets full sweep period in seconds.
 
RealType firstFrequency (RealType carrier_frequency) const noexcept
 Gets first-step RF frequency in hertz.
 
RealType lastFrequency (RealType carrier_frequency) const noexcept
 Gets final-step RF frequency in hertz.
 
RealType frequencySpan () const noexcept
 Gets first-to-last absolute span in hertz.
 
RealType effectiveBandwidth () const noexcept
 Gets DFT-convention effective bandwidth in hertz.
 
std::optional< RealTypetotalDuration () const noexcept
 Gets finite waveform duration, if sweep_count is configured.
 
std::optional< StepStateactiveStepAt (RealType time_since_segment_start, RealType carrier_frequency) const noexcept
 Returns the active step for a time since the segment start.
 
std::vector< ComplexTyperender (const std::vector< interp::InterpPoint > &points, unsigned &size, RealType fracWinDelay) const override
 Renders the signal data. For SFCW signals, this is a no-op.
 
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.
 
virtual bool isFmcwFamily () const noexcept
 Returns true when this signal belongs to the FMCW waveform family.
 

Detailed Description

Stepped-frequency continuous-wave signal implementation.

Definition at line 313 of file radar_signal.h.

Constructor & Destructor Documentation

◆ SteppedFrequencySignal() [1/3]

fers_signal::SteppedFrequencySignal::SteppedFrequencySignal ( RealType  start_frequency_offset,
RealType  step_size,
std::size_t  step_count,
RealType  dwell_time,
RealType  step_period,
std::optional< std::size_t >  sweep_count = std::nullopt 
)

Constructs a uniform stepped-frequency CW signal.

Definition at line 55 of file radar_signal.cpp.

57 :
58 _start_frequency_offset(start_frequency_offset), _step_size(step_size), _step_count(step_count),
59 _dwell_time(dwell_time), _step_period(step_period), _sweep_count(sweep_count)
60 {
61 }

◆ ~SteppedFrequencySignal()

fers_signal::SteppedFrequencySignal::~SteppedFrequencySignal ( )
overridedefault

◆ SteppedFrequencySignal() [2/3]

fers_signal::SteppedFrequencySignal::SteppedFrequencySignal ( const SteppedFrequencySignal )
deletenoexcept

◆ SteppedFrequencySignal() [3/3]

fers_signal::SteppedFrequencySignal::SteppedFrequencySignal ( SteppedFrequencySignal &&  )
deletenoexcept

Member Function Documentation

◆ activeStepAt()

std::optional< SteppedFrequencySignal::StepState > fers_signal::SteppedFrequencySignal::activeStepAt ( RealType  time_since_segment_start,
RealType  carrier_frequency 
) const
noexcept

Returns the active step for a time since the segment start.

Definition at line 101 of file radar_signal.cpp.

103 {
104 if (time_since_segment_start < 0.0 || _step_count == 0 || _step_period <= 0.0 || _dwell_time <= 0.0)
105 {
106 return std::nullopt;
107 }
108
109 const RealType sweep_period = getSweepPeriod();
110 const auto sweep_index = static_cast<std::size_t>(std::floor(time_since_segment_start / sweep_period));
111 if (_sweep_count.has_value() && sweep_index >= *_sweep_count)
112 {
113 return std::nullopt;
114 }
115
116 const RealType local_sweep_time = time_since_segment_start - static_cast<RealType>(sweep_index) * sweep_period;
117 const auto step_index = static_cast<std::size_t>(std::floor(local_sweep_time / _step_period));
118 if (step_index >= _step_count)
119 {
120 return std::nullopt;
121 }
122
123 const RealType step_start_time =
124 static_cast<RealType>(sweep_index) * sweep_period + static_cast<RealType>(step_index) * _step_period;
125 const RealType local_step_time = time_since_segment_start - step_start_time;
127 {
128 return std::nullopt;
129 }
130
131 return StepState{.step_index = step_index,
132 .sweep_index = sweep_index,
133 .step_start_time = step_start_time,
134 .dwell_end_time = step_start_time + _dwell_time,
135 .step_end_time = step_start_time + _step_period,
136 .rf_frequency =
137 firstFrequency(carrier_frequency) + static_cast<RealType>(step_index) * _step_size};
138 }
RealType getSweepPeriod() const noexcept
Gets full sweep period in seconds.
RealType firstFrequency(RealType carrier_frequency) const noexcept
Gets first-step RF frequency in hertz.
double RealType
Type for real numbers.
Definition config.h:27
math::Vec3 max

References max, and fers_signal::SteppedFrequencySignal::StepState::step_index.

◆ 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:

◆ effectiveBandwidth()

RealType fers_signal::SteppedFrequencySignal::effectiveBandwidth ( ) const
noexcept

Gets DFT-convention effective bandwidth in hertz.

Definition at line 86 of file radar_signal.cpp.

87 {
88 return static_cast<RealType>(_step_count) * std::abs(_step_size);
89 }

◆ firstFrequency()

RealType fers_signal::SteppedFrequencySignal::firstFrequency ( RealType  carrier_frequency) const
noexcept

Gets first-step RF frequency in hertz.

Definition at line 63 of file radar_signal.cpp.

64 {
65 return carrier_frequency + _start_frequency_offset;
66 }

◆ frequencySpan()

RealType fers_signal::SteppedFrequencySignal::frequencySpan ( ) const
noexcept

Gets first-to-last absolute span in hertz.

Definition at line 77 of file radar_signal.cpp.

78 {
79 if (_step_count == 0)
80 {
81 return 0.0;
82 }
83 return std::abs(static_cast<RealType>(_step_count - 1U) * _step_size);
84 }

◆ getDwellTime()

RealType fers_signal::SteppedFrequencySignal::getDwellTime ( ) const
noexcept

Gets active dwell time per step in seconds.

Definition at line 352 of file radar_signal.h.

352{ return _dwell_time; }

◆ 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; }

◆ getStartFrequencyOffset()

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

Gets the first-step offset from carrier in hertz.

Definition at line 343 of file radar_signal.h.

343{ return _start_frequency_offset; }

◆ getStepCount()

std::size_t fers_signal::SteppedFrequencySignal::getStepCount ( ) const
noexcept

Gets the number of steps per sweep.

Definition at line 349 of file radar_signal.h.

349{ return _step_count; }

◆ getStepPeriod()

RealType fers_signal::SteppedFrequencySignal::getStepPeriod ( ) const
noexcept

Gets step repetition period in seconds.

Definition at line 355 of file radar_signal.h.

355{ return _step_period; }

◆ getStepSize()

RealType fers_signal::SteppedFrequencySignal::getStepSize ( ) const
noexcept

Gets the uniform frequency step in hertz.

Definition at line 346 of file radar_signal.h.

346{ return _step_size; }

◆ getSweepCount()

const std::optional< std::size_t > & fers_signal::SteppedFrequencySignal::getSweepCount ( ) const
noexcept

Gets optional finite sweep count.

Definition at line 358 of file radar_signal.h.

358{ return _sweep_count; }

◆ getSweepPeriod()

RealType fers_signal::SteppedFrequencySignal::getSweepPeriod ( ) const
noexcept

Gets full sweep period in seconds.

Definition at line 361 of file radar_signal.h.

362 {
363 return static_cast<RealType>(_step_count) * _step_period;
364 }

Referenced by totalDuration().

+ Here is the caller graph for this function:

◆ isFmcwFamily()

virtual bool fers_signal::Signal::isFmcwFamily ( ) const
virtualnoexceptinherited

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

Reimplemented in fers_signal::FmcwChirpSignal, and fers_signal::FmcwTriangleSignal.

Definition at line 109 of file radar_signal.h.

109{ return false; }

◆ lastFrequency()

RealType fers_signal::SteppedFrequencySignal::lastFrequency ( RealType  carrier_frequency) const
noexcept

Gets final-step RF frequency in hertz.

Definition at line 68 of file radar_signal.cpp.

69 {
70 if (_step_count == 0)
71 {
72 return firstFrequency(carrier_frequency);
73 }
74 return firstFrequency(carrier_frequency) + static_cast<RealType>(_step_count - 1U) * _step_size;
75 }

◆ 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]

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

◆ operator=() [2/2]

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

◆ render()

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

Renders the signal data. For SFCW signals, this is a no-op.

Reimplemented from fers_signal::Signal.

Definition at line 140 of file radar_signal.cpp.

142 {
143 size = 0;
144 return {};
145 }

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:

◆ totalDuration()

std::optional< RealType > fers_signal::SteppedFrequencySignal::totalDuration ( ) const
noexcept

Gets finite waveform duration, if sweep_count is configured.

Definition at line 91 of file radar_signal.cpp.

92 {
93 if (!_sweep_count.has_value())
94 {
95 return std::nullopt;
96 }
97 return static_cast<RealType>(*_sweep_count) * getSweepPeriod();
98 }

References getSweepPeriod().

+ Here is the call graph for this function:

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