FERS 0.1.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
core Namespace Reference

Classes

struct  ActiveStreamingSource
 Cached description of an active streaming transmitter segment. More...
 
struct  ByteProjection
 Describes a projected byte count and whether it saturated during arithmetic. More...
 
class  Config
 Configuration structure for the application. More...
 
struct  Event
 Represents a single event in the simulation's time-ordered queue. More...
 
struct  EventComparator
 A custom comparator for the event priority queue. More...
 
struct  FmcwChirpBoundaryTracker
 Tracks the current FMCW chirp boundary for a streaming path. More...
 
struct  FmcwMetadata
 FMCW waveform metadata captured for a streaming output file. More...
 
struct  FmcwSourceMetadata
 Metadata for one FMCW illuminator represented in a streaming output file. More...
 
struct  FmcwSourceSegmentMetadata
 Metadata for one active FMCW transmitter schedule segment. More...
 
struct  FmcwTriangleBoundaryTracker
 Tracks the current FMCW triangle leg boundary for a streaming path. More...
 
struct  OutputConfig
 
struct  OutputFileMetadata
 Metadata for one receiver output file. More...
 
struct  OutputMetadata
 Metadata summary for the full simulation output set. More...
 
class  OutputMetadataCollector
 Thread-safe collector for simulation output metadata. More...
 
struct  OutputStats
 
class  ProgressReporter
 A thread-safe wrapper for the simulation progress callback. More...
 
struct  PulseChunkMetadata
 Metadata for one pulsed output chunk written to HDF5. More...
 
struct  ReceiverOutputPacketTrace
 
class  ReceiverOutputSink
 
struct  ReceiverSampleBlock
 
struct  ReceiverStreamDescriptor
 
struct  ReceiverStreamStats
 
struct  ReceiverTrackerCache
 Per-receiver FMCW tracker state for direct and reflected streaming paths. More...
 
struct  RenderingJob
 A data packet containing all information needed to process one receive window. More...
 
struct  SfcwMetadata
 SFCW waveform metadata captured for a streaming output file. More...
 
struct  SfcwSourceMetadata
 Metadata for one SFCW illuminator represented in a streaming output file. More...
 
struct  SfcwSourceSegmentMetadata
 Metadata for one active SFCW transmitter schedule segment. More...
 
class  SimulationEngine
 Encapsulates the state and logic of the event-driven simulation loop. More...
 
struct  SimulationMemoryProjection
 Captures startup memory and rendered-output projections for a simulation. More...
 
struct  SimulationState
 Holds the dynamic global state of the simulation. More...
 
struct  StreamingSegmentMetadata
 Metadata for one contiguous streaming output segment. More...
 
struct  StreamingWaveformTracker
 Tracks the current streaming waveform boundary for a path. More...
 
struct  Vita49OutputConfig
 
struct  Vita49OutputMetadata
 Metadata for the VITA 49.2 UDP output backend. More...
 
struct  Vita49StreamMetadata
 Metadata for one VITA 49.2 receiver stream. More...
 
struct  Vita49Timestamp
 
class  World
 The World class manages the simulator environment. More...
 

Typedefs

using ReceiverOutputTelemetryCallback = std::function< void(const std::optional< OutputStats > &, std::span< const ReceiverOutputPacketTrace >)>
 

Enumerations

enum class  OutputMode : std::uint8_t { Hdf5 , Vita49Udp }
 
enum class  EventType : std::uint8_t {
  TX_PULSED_START , RX_PULSED_WINDOW_START , RX_PULSED_WINDOW_END , TX_STREAMING_START ,
  TX_STREAMING_END , RX_STREAMING_START , RX_STREAMING_END
}
 Enumerates the types of events that can occur in the simulation. More...
 
enum class  StreamingWaveformKind : std::uint8_t { Cw , FmcwLinear , FmcwTriangle , Sfcw }
 Streaming waveform shape cached for a currently active source. More...
 

Functions

std::vector< std::shared_ptr< timing::Timing > > collectCwPhaseNoiseTimings (const World &world)
 Collects unique timing sources used by CW/FMCW transmitters and receivers.
 
void addStreamingReceiverProjection (SimulationMemoryProjection &projection, const radar::Receiver &receiver, const bool sample_count_overflowed)
 
void addPulsedReceiverProjection (SimulationMemoryProjection &projection, const radar::Receiver &receiver)
 
SimulationMemoryProjection projectSimulationMemory (const World &world)
 Projects startup memory and rendered-output sizes for a simulation world.
 
std::string formatByteSize (std::uint64_t bytes)
 Formats a byte count using binary units.
 
std::string memoryProjectionToJsonString (const SimulationMemoryProjection &projection)
 Serializes a simulation memory projection as JSON.
 
void logSimulationMemoryProjection (const World &world)
 Logs the projected simulation memory footprint for the provided world.
 
bool isVita49Enabled (const OutputConfig &config) noexcept
 
std::string outputFileMetadataToJsonString (const OutputFileMetadata &metadata)
 Serializes one output-file metadata entry to JSON.
 
std::string outputMetadataToJsonString (const OutputMetadata &metadata)
 Serializes a full simulation output metadata snapshot to JSON.
 
Vita49OutputMetadata vita49MetadataFromConfig (const Vita49OutputConfig &config)
 Builds the static VITA metadata section from runtime output configuration.
 
RealType besselJ1 (const RealType x) noexcept
 Computes the Bessel function of the first kind (order 1) for a given value.
 
unsigned countProcessors () noexcept
 Detects the number of CPUs on the machine.
 
std::string toString (const EventType type)
 Converts an EventType enum to its string representation.
 
OutputMetadata runEventDrivenSim (World *world, pool::ThreadPool &pool, const std::function< void(const std::string &, int, int)> &progress_callback, const std::string &output_dir, const OutputConfig &output_config=OutputConfig{}, std::function< bool()> cancel_callback=nullptr, bool *cancelled=nullptr, ReceiverOutputTelemetryCallback telemetry_callback=nullptr)
 Runs the unified, event-driven radar simulation.
 
ActiveStreamingSource makeActiveSource (const radar::Transmitter *tx, RealType segment_start, RealType segment_end)
 Builds an active-source cache from a streaming transmitter and segment bounds.
 
ActiveStreamingSource makeActiveSourceFromWaveform (const fers_signal::RadarSignal *signal, RealType segment_start, RealType segment_end)
 Builds an active-source cache directly from a waveform for receiver-local LO references.
 
std::optional< RealTypefirstFmcwChirpStart (const ActiveStreamingSource &source, RealType active_start, RealType active_end)
 Returns the first FMCW chirp start inside the absolute interval, if one exists.
 
std::uint64_t countFmcwChirpStarts (const ActiveStreamingSource &source, RealType active_start, RealType active_end)
 Counts FMCW chirps that start inside the absolute interval.
 
std::optional< RealTypefirstFmcwTriangleStart (const ActiveStreamingSource &source, RealType active_start, RealType active_end)
 Returns the first FMCW triangle start inside the absolute interval, if one exists.
 
std::uint64_t countFmcwTriangleStarts (const ActiveStreamingSource &source, RealType active_start, RealType active_end)
 Counts FMCW triangles that start inside the absolute interval.
 
std::optional< RealTypefirstSfcwStepStart (const ActiveStreamingSource &source, RealType active_start, RealType active_end)
 Returns the first SFCW step start inside the absolute interval, if one exists.
 
std::uint64_t countSfcwStepStarts (const ActiveStreamingSource &source, RealType active_start, RealType active_end)
 Counts SFCW active dwells that start inside the absolute interval.
 
void showHelp (const char *programName) noexcept
 Displays the help message.
 
void showVersion () noexcept
 Displays the version information.
 
std::expected< Config, std::string > parseArguments (int argc, char *argv[]) noexcept
 Parses command-line arguments.
 
std::filesystem::path resolveOutputDir (const std::string &script_file, const std::optional< std::string > &output_dir) noexcept
 Resolves the final simulation output directory from CLI arguments.
 
std::filesystem::path resolveKmlOutputPath (const std::string &script_file, const std::filesystem::path &final_output_dir, const std::optional< std::string > &kml_file) noexcept
 Resolves the KML output file path from CLI arguments and output directory.
 

Typedef Documentation

◆ ReceiverOutputTelemetryCallback

Definition at line 196 of file receiver_output.h.

Enumeration Type Documentation

◆ EventType

enum class core::EventType : std::uint8_t
strong

Enumerates the types of events that can occur in the simulation.

Enumerator
TX_PULSED_START 

A pulsed transmitter begins emitting a pulse.

RX_PULSED_WINDOW_START 

A pulsed receiver opens its listening window.

RX_PULSED_WINDOW_END 

A pulsed receiver closes its listening window.

TX_STREAMING_START 

A streaming transmitter starts transmitting.

TX_STREAMING_END 

A streaming transmitter stops transmitting.

RX_STREAMING_START 

A streaming receiver starts listening.

RX_STREAMING_END 

A streaming receiver stops listening.

Definition at line 29 of file sim_events.h.

30 {
31 TX_PULSED_START, ///< A pulsed transmitter begins emitting a pulse.
32 RX_PULSED_WINDOW_START, ///< A pulsed receiver opens its listening window.
33 RX_PULSED_WINDOW_END, ///< A pulsed receiver closes its listening window.
34 TX_STREAMING_START, ///< A streaming transmitter starts transmitting.
35 TX_STREAMING_END, ///< A streaming transmitter stops transmitting.
36 RX_STREAMING_START, ///< A streaming receiver starts listening.
37 RX_STREAMING_END, ///< A streaming receiver stops listening.
38 };
@ RX_PULSED_WINDOW_START
A pulsed receiver opens its listening window.
@ RX_PULSED_WINDOW_END
A pulsed receiver closes its listening window.
@ TX_STREAMING_END
A streaming transmitter stops transmitting.
@ RX_STREAMING_END
A streaming receiver stops listening.
@ TX_STREAMING_START
A streaming transmitter starts transmitting.
@ TX_PULSED_START
A pulsed transmitter begins emitting a pulse.
@ RX_STREAMING_START
A streaming receiver starts listening.

◆ OutputMode

enum class core::OutputMode : std::uint8_t
strong
Enumerator
Hdf5 
Vita49Udp 

Definition at line 17 of file output_config.h.

◆ StreamingWaveformKind

enum class core::StreamingWaveformKind : std::uint8_t
strong

Streaming waveform shape cached for a currently active source.

Enumerator
Cw 
FmcwLinear 
FmcwTriangle 
Sfcw 

Definition at line 33 of file simulation_state.h.

Function Documentation

◆ addPulsedReceiverProjection()

void core::addPulsedReceiverProjection ( SimulationMemoryProjection projection,
const radar::Receiver receiver 
)

Definition at line 366 of file memory_projection.cpp.

367 {
368 ++projection.pulsed_receiver_count;
369 bool window_count_overflowed = false;
371 projection.pulsed_window_count = addBytes({.bytes = projection.pulsed_window_count},
372 {.bytes = windows, .overflowed = window_count_overflowed})
373 .bytes;
374
377 receiver.getWindowLength(), projection.simulation_sample_rate_hz, pulsed_sample_count_overflowed);
379 const auto rendered_samples =
381 projection.rendered_hdf5_sample_count =
382 addBytes({.bytes = projection.rendered_hdf5_sample_count}, rendered_samples).bytes;
383 }
const Receiver & receiver
math::Vec3 max

References max, and receiver.

Referenced by projectSimulationMemory().

+ Here is the caller graph for this function:

◆ addStreamingReceiverProjection()

void core::addStreamingReceiverProjection ( SimulationMemoryProjection projection,
const radar::Receiver receiver,
const bool  sample_count_overflowed 
)

Definition at line 341 of file memory_projection.cpp.

343 {
344 ++projection.streaming_receiver_count;
345 bool if_count_overflowed = false;
346 const auto if_sample_rate = receiver.getIfSampleRate();
347 const bool if_rate_dechirped = receiver.isDechirpEnabled() && if_sample_rate.has_value();
349 ? countSamplesForDuration(projection.duration_seconds, if_sample_rate.value_or(0.0), if_count_overflowed)
350 : std::uint64_t{0};
353 : (receiver.isDechirpEnabled() ? projection.streaming_sample_count
354 : downsampledSampleCount(projection.streaming_sample_count));
355 projection.rendered_hdf5_sample_count =
356 addBytes({.bytes = projection.rendered_hdf5_sample_count},
358 .bytes;
359 const auto resident_samples = if_rate_dechirped ? if_sample_count : projection.streaming_sample_count;
360 projection.streaming_iq_buffers =
361 addBytes(projection.streaming_iq_buffers,
362 multiplyBytes(resident_samples, static_cast<std::uint64_t>(sizeof(ComplexType)),
364 }
std::complex< RealType > ComplexType
Type for complex numbers.
Definition config.h:35

References max, and receiver.

Referenced by projectSimulationMemory().

+ Here is the caller graph for this function:

◆ besselJ1()

RealType core::besselJ1 ( const RealType  x)
noexcept

Computes the Bessel function of the first kind (order 1) for a given value.

Parameters
xThe value for which the Bessel function is to be computed.
Returns
The computed value of the Bessel function of the first kind (order 1).

Definition at line 28 of file portable_utils.h.

29 {
30#ifdef _MSC_VER
31 return _j1(x);
32#else
33 return j1(x);
34#endif
35 }

References max.

◆ collectCwPhaseNoiseTimings()

std::vector< std::shared_ptr< timing::Timing > > core::collectCwPhaseNoiseTimings ( const World world)

Collects unique timing sources used by CW/FMCW transmitters and receivers.

Parameters
worldThe simulation world to inspect.
Returns
A vector of unique timing sources that may need phase-noise lookup tables.

Definition at line 310 of file memory_projection.cpp.

311 {
312 std::unordered_map<SimId, std::shared_ptr<timing::Timing>> unique_timings;
313
314 for (const auto& transmitter_ptr : world.getTransmitters())
315 {
316 if (!transmitter_ptr->isStreamingMode())
317 {
318 continue;
319 }
320 unique_timings.try_emplace(transmitter_ptr->getTiming()->getId(), transmitter_ptr->getTiming());
321 }
322
323 for (const auto& receiver_ptr : world.getReceivers())
324 {
326 {
327 continue;
328 }
329 unique_timings.try_emplace(receiver_ptr->getTiming()->getId(), receiver_ptr->getTiming());
330 }
331
332 std::vector<std::shared_ptr<timing::Timing>> timings;
333 timings.reserve(unique_timings.size());
334 for (const auto& entry : unique_timings)
335 {
336 timings.push_back(entry.second);
337 }
338 return timings;
339 }

References core::World::getReceivers(), core::World::getTransmitters(), and max.

Referenced by projectSimulationMemory().

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

◆ countFmcwChirpStarts()

std::uint64_t core::countFmcwChirpStarts ( const ActiveStreamingSource source,
const RealType  active_start,
const RealType  active_end 
)

Counts FMCW chirps that start inside the absolute interval.

Definition at line 303 of file simulation_state.cpp.

305 {
307 if (!first_index.has_value())
308 {
309 return 0;
310 }
311
312 const RealType clipped_end = std::min(active_end, source.segment_end);
313 const RealType first_start = source.segment_start + static_cast<RealType>(*first_index) * source.chirp_period;
315 if (!source.chirp_count.has_value())
316 {
317 return starts_in_interval;
318 }
319
320 const auto configured = static_cast<std::uint64_t>(*source.chirp_count);
321 return std::min(starts_in_interval, configured - *first_index);
322 }
double RealType
Type for real numbers.
Definition config.h:27
RealType segment_start
Segment start time in seconds.
RealType chirp_period
Cached FMCW chirp period in seconds.
std::optional< std::size_t > chirp_count
Optional finite chirp count for the segment.
RealType segment_end
Segment end time in seconds.

References core::ActiveStreamingSource::chirp_count, core::ActiveStreamingSource::chirp_period, max, core::ActiveStreamingSource::segment_end, and core::ActiveStreamingSource::segment_start.

◆ countFmcwTriangleStarts()

std::uint64_t core::countFmcwTriangleStarts ( const ActiveStreamingSource source,
const RealType  active_start,
const RealType  active_end 
)

Counts FMCW triangles that start inside the absolute interval.

Definition at line 335 of file simulation_state.cpp.

337 {
339 if (!first_index.has_value())
340 {
341 return 0;
342 }
343
344 const RealType clipped_end = std::min(active_end, source.segment_end);
345 const RealType first_start =
346 source.segment_start + static_cast<RealType>(*first_index) * source.triangle_period;
348 if (!source.triangle_count.has_value())
349 {
350 return starts_in_interval;
351 }
352
353 const auto configured = static_cast<std::uint64_t>(*source.triangle_count);
354 return std::min(starts_in_interval, configured - *first_index);
355 }
RealType triangle_period
Cached full triangle period in seconds.
std::optional< std::size_t > triangle_count
Optional finite triangle count for the segment.

References max, core::ActiveStreamingSource::segment_end, core::ActiveStreamingSource::segment_start, core::ActiveStreamingSource::triangle_count, and core::ActiveStreamingSource::triangle_period.

◆ countProcessors()

unsigned core::countProcessors ( )
noexcept

Detects the number of CPUs on the machine.

Returns
The number of CPUs detected, or 1 if detection fails.

Definition at line 42 of file portable_utils.h.

43 {
44 if (const unsigned hardware_threads = std::thread::hardware_concurrency(); hardware_threads > 0)
45 {
46 return hardware_threads;
47 }
48 LOG(logging::Level::ERROR, "Unable to get CPU count, assuming 1.");
49 return 1;
50 }
#define LOG(level,...)
Definition logging.h:19
@ ERROR
Error level for error events.

References logging::ERROR, LOG, and max.

◆ countSfcwStepStarts()

std::uint64_t core::countSfcwStepStarts ( const ActiveStreamingSource source,
const RealType  active_start,
const RealType  active_end 
)

Counts SFCW active dwells that start inside the absolute interval.

Definition at line 368 of file simulation_state.cpp.

370 {
372 if (!first_index.has_value())
373 {
374 return 0;
375 }
376
377 const RealType clipped_end = std::min(active_end, source.segment_end);
378 const RealType first_start =
379 source.segment_start + static_cast<RealType>(*first_index) * source.sfcw_step_period;
381 if (!source.sfcw_sweep_count.has_value())
382 {
383 return starts_in_interval;
384 }
385
386 const auto configured = static_cast<std::uint64_t>(*source.sfcw_sweep_count) * source.sfcw_step_count;
387 return std::min(starts_in_interval, configured - *first_index);
388 }
std::size_t sfcw_step_count
Cached SFCW steps per sweep.
std::optional< std::size_t > sfcw_sweep_count
Optional finite SFCW sweep count for the segment.
RealType sfcw_step_period
Cached SFCW step period in seconds.

References max, core::ActiveStreamingSource::segment_end, core::ActiveStreamingSource::segment_start, core::ActiveStreamingSource::sfcw_step_count, core::ActiveStreamingSource::sfcw_step_period, and core::ActiveStreamingSource::sfcw_sweep_count.

◆ firstFmcwChirpStart()

std::optional< RealType > core::firstFmcwChirpStart ( const ActiveStreamingSource source,
const RealType  active_start,
const RealType  active_end 
)

Returns the first FMCW chirp start inside the absolute interval, if one exists.

Definition at line 292 of file simulation_state.cpp.

294 {
296 if (!first_index.has_value())
297 {
298 return std::nullopt;
299 }
300 return source.segment_start + static_cast<RealType>(*first_index) * source.chirp_period;
301 }

References core::ActiveStreamingSource::chirp_period, max, and core::ActiveStreamingSource::segment_start.

◆ firstFmcwTriangleStart()

std::optional< RealType > core::firstFmcwTriangleStart ( const ActiveStreamingSource source,
const RealType  active_start,
const RealType  active_end 
)

Returns the first FMCW triangle start inside the absolute interval, if one exists.

Definition at line 324 of file simulation_state.cpp.

326 {
328 if (!first_index.has_value())
329 {
330 return std::nullopt;
331 }
332 return source.segment_start + static_cast<RealType>(*first_index) * source.triangle_period;
333 }

References max, core::ActiveStreamingSource::segment_start, and core::ActiveStreamingSource::triangle_period.

◆ firstSfcwStepStart()

std::optional< RealType > core::firstSfcwStepStart ( const ActiveStreamingSource source,
const RealType  active_start,
const RealType  active_end 
)

Returns the first SFCW step start inside the absolute interval, if one exists.

Definition at line 357 of file simulation_state.cpp.

359 {
361 if (!first_index.has_value())
362 {
363 return std::nullopt;
364 }
365 return source.segment_start + static_cast<RealType>(*first_index) * source.sfcw_step_period;
366 }

References max, core::ActiveStreamingSource::segment_start, and core::ActiveStreamingSource::sfcw_step_period.

◆ formatByteSize()

std::string core::formatByteSize ( std::uint64_t  bytes)

Formats a byte count using binary units.

Parameters
bytesThe byte count to format.
Returns
A human-readable string such as 512 B or 1.50 MiB.

Definition at line 456 of file memory_projection.cpp.

457 {
458 constexpr std::array units = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"};
459 auto value = static_cast<long double>(bytes);
460 std::size_t unit_index = 0;
461 while (value >= 1024.0L && unit_index + 1 < units.size())
462 {
463 value /= 1024.0L;
464 ++unit_index;
465 }
466 if (unit_index == 0)
467 {
468 return std::format("{} {}", bytes, units.at(unit_index));
469 }
470 return std::format("{:.2f} {}", static_cast<double>(value), units.at(unit_index));
471 }

References max.

Referenced by logSimulationMemoryProjection(), and memoryProjectionToJsonString().

+ Here is the caller graph for this function:

◆ isVita49Enabled()

bool core::isVita49Enabled ( const OutputConfig config)
noexcept

Definition at line 40 of file output_config.h.

41 {
42 return config.mode == OutputMode::Vita49Udp;
43 }

References max, and Vita49Udp.

Referenced by runEventDrivenSim().

+ Here is the caller graph for this function:

◆ logSimulationMemoryProjection()

void core::logSimulationMemoryProjection ( const World world)

Logs the projected simulation memory footprint for the provided world.

Parameters
worldThe simulation world to inspect and report.

Definition at line 502 of file memory_projection.cpp.

503 {
504 const auto projection = projectSimulationMemory(world);
505 const std::string resident_baseline =
506 projection.resident_baseline.has_value() ? formatByteSize(projection.resident_baseline->bytes) : "unknown";
507 const std::string total = projection.projected_total_footprint.has_value()
508 ? formatByteSize(projection.projected_total_footprint->bytes)
509 : "unknown";
510
512 "Projected simulation footprint: phase_noise_lookup_memory={} ({} enabled timing sources x {} samples), "
513 "streaming_output_buffer_memory={} ({} streaming receivers, IF-rate receivers use IF sample counts), "
514 "rendered_hdf5_dataset_payload={} "
515 "({} output samples), resident_baseline={} (current RSS before projected run allocations), "
516 "projected_total_footprint={}.",
517 formatByteSize(projection.phase_noise_lookup.bytes), projection.enabled_phase_noise_timing_count,
518 projection.phase_noise_sample_count, formatByteSize(projection.streaming_iq_buffers.bytes),
519 projection.streaming_receiver_count, formatByteSize(projection.rendered_hdf5_payload.bytes),
520 projection.rendered_hdf5_sample_count, resident_baseline, total);
521
522 constexpr std::uint64_t one_gib = 1024ULL * 1024ULL * 1024ULL;
523 for (const auto& receiver_ptr : world.getReceivers())
524 {
525 const auto& receiver = *receiver_ptr;
526 if (!receiver.isDechirpEnabled())
527 {
528 continue;
529 }
530 if (receiver.hasFmcwIfSampleRate())
531 {
532 continue;
533 }
534 const auto projected_payload =
535 multiplyBytes(projection.streaming_sample_count, 2ULL * static_cast<std::uint64_t>(sizeof(RealType)));
536 if (projected_payload.bytes > one_gib || projected_payload.overflowed)
537 {
538 const auto gib = static_cast<long double>(projected_payload.bytes) / static_cast<long double>(one_gib);
539 // TODO: UI workflows should have disk+memory usage stats on the SimulationView page (shows before user
540 // runs the sim)
542 "Receiver {} is outputting RF-rate IF data. Projected file size is {:.2f} GiB. This is expected "
543 "for V1 native dechirping, but ensure you have sufficient disk space. Future versions will support "
544 "IF-rate decimation.",
545 receiver.getName(), static_cast<double>(gib));
546 }
547 }
548 }
SimulationMemoryProjection projectSimulationMemory(const World &world)
Projects startup memory and rendered-output sizes for a simulation world.
std::string formatByteSize(const std::uint64_t bytes)
Formats a byte count using binary units.
@ WARNING
Warning level for potentially harmful situations.
@ DEBUG
Debug level for general debugging information.

References logging::DEBUG, formatByteSize(), core::World::getReceivers(), LOG, max, projectSimulationMemory(), receiver, and logging::WARNING.

Referenced by core::SimulationEngine::run().

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

◆ makeActiveSource()

ActiveStreamingSource core::makeActiveSource ( const radar::Transmitter *const  tx,
const RealType  segment_start,
const RealType  segment_end 
)

Builds an active-source cache from a streaming transmitter and segment bounds.

Definition at line 249 of file simulation_state.cpp.

251 {
252 ActiveStreamingSource source{};
253 source.transmitter = tx;
254 source.segment_start = segment_start;
255 source.segment_end = segment_end;
256 if (tx == nullptr)
257 {
258 return source;
259 }
260
261 const auto* const signal = tx->getSignal();
262 if (signal == nullptr)
263 {
264 return source;
265 }
266
267 const RealType raw_segment_end = segment_end;
268 populateWaveformCache(source, signal, segment_start);
269 if (source.kind == StreamingWaveformKind::FmcwTriangle &&
271 {
272 const auto emitted_triangles = static_cast<std::uint64_t>(
273 std::max<RealType>(0.0, (source.segment_end - segment_start) / source.triangle_period));
275 "FMCW triangle transmitter '{}' segment [{}, {}] emits {} complete triangles and drops {} s of "
276 "leftover active time.",
277 tx->getName(), segment_start, raw_segment_end, emitted_triangles, raw_segment_end - source.segment_end);
278 }
279 return source;
280 }
Cached description of an active streaming transmitter segment.
const radar::Transmitter * transmitter
Transmitter active during this segment.

References FmcwTriangle, LOG, max, core::ActiveStreamingSource::transmitter, and logging::WARNING.

◆ makeActiveSourceFromWaveform()

ActiveStreamingSource core::makeActiveSourceFromWaveform ( const fers_signal::RadarSignal *const  signal,
const RealType  segment_start,
const RealType  segment_end 
)

Builds an active-source cache directly from a waveform for receiver-local LO references.

Definition at line 282 of file simulation_state.cpp.

284 {
285 ActiveStreamingSource source{};
286 source.segment_start = segment_start;
287 source.segment_end = segment_end;
288 populateWaveformCache(source, signal, segment_start);
289 return source;
290 }

References max, and core::ActiveStreamingSource::segment_start.

◆ memoryProjectionToJsonString()

std::string core::memoryProjectionToJsonString ( const SimulationMemoryProjection projection)

Serializes a simulation memory projection as JSON.

Parameters
projectionThe projection to serialize.
Returns
A formatted JSON string suitable for API responses and diagnostics.

Definition at line 473 of file memory_projection.cpp.

474 {
475 const nlohmann::json result = {
476 {"duration_seconds", projection.duration_seconds},
477 {"simulation_sample_rate_hz", projection.simulation_sample_rate_hz},
478 {"oversample_ratio", projection.oversample_ratio},
479 {"sample_counts",
480 {{"streaming_samples", projection.streaming_sample_count},
481 {"phase_noise_samples_per_enabled_timing", projection.phase_noise_sample_count},
482 {"rendered_hdf5_samples", projection.rendered_hdf5_sample_count},
483 {"pulsed_windows", projection.pulsed_window_count}}},
484 {"object_counts",
485 {{"phase_noise_timing_sources", projection.phase_noise_timing_count},
486 {"enabled_phase_noise_timing_sources", projection.enabled_phase_noise_timing_count},
487 {"streaming_receivers", projection.streaming_receiver_count},
488 {"pulsed_receivers", projection.pulsed_receiver_count}}},
489 {"phase_noise_lookups", byteProjectionToJson(projection.phase_noise_lookup)},
490 {"streaming_iq_buffers", byteProjectionToJson(projection.streaming_iq_buffers)},
491 {"rendered_hdf5_dataset_payload", byteProjectionToJson(projection.rendered_hdf5_payload)},
492 {"current_resident_set",
493 projection.current_resident_set.has_value()
494 ? nlohmann::json{{"bytes", *projection.current_resident_set},
495 {"human", formatByteSize(*projection.current_resident_set)}}
496 : nlohmann::json{{"bytes", nullptr}, {"human", "unknown"}}},
497 {"resident_baseline", optionalByteProjectionToJson(projection.resident_baseline)},
498 {"projected_total_footprint", optionalByteProjectionToJson(projection.projected_total_footprint)}};
499 return result.dump(2);
500 }

References formatByteSize(), and max.

Referenced by fers_get_memory_projection_json().

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

◆ outputFileMetadataToJsonString()

std::string core::outputFileMetadataToJsonString ( const OutputFileMetadata metadata)

Serializes one output-file metadata entry to JSON.

Definition at line 431 of file output_metadata.cpp.

432 {
433 return fileToJson(metadata).dump(2);
434 }

References max, and outputFileMetadataToJsonString().

Referenced by outputFileMetadataToJsonString().

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

◆ outputMetadataToJsonString()

std::string core::outputMetadataToJsonString ( const OutputMetadata metadata)

Serializes a full simulation output metadata snapshot to JSON.

Definition at line 436 of file output_metadata.cpp.

436{ return metadataToJson(metadata).dump(2); }

References max, and outputMetadataToJsonString().

Referenced by FersContext::getLastOutputMetadataJson(), and outputMetadataToJsonString().

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

◆ parseArguments()

std::expected< Config, std::string > core::parseArguments ( int  argc,
char argv[] 
)
noexcept

Parses command-line arguments.

Processes the command-line arguments, validating them and extracting configurations like script file, logging level, and thread count.

Parameters
argcThe argument count.
argvThe argument vector.
Returns
std::expected<Config, std::string> Parsed configuration or an error message.

Definition at line 425 of file arg_parser.cpp.

430 :
432
433Example:
434 )" << programName
435 << R"( simulation.fersxml --out-dir=./results --log-level=DEBUG -n=4
436
439)";
440 }
441
442 void showVersion() noexcept
443 {
444 const char* version = fers_get_version();
445
446 std::cout << '\n'
447 << "/------------------------------------------------\\\n"
448 << "| FERS - The Flexible Extensible Radar Simulator |\n"
449 << std::format("| Version {:<40}|\n", version)
450 << "| Authors: Marc Brooker, Michael Inggs, |\n"
451 << "| and FERS Contributors |\n"
452 << "\\------------------------------------------------/\n\n";
453 }
454
455 std::expected<Config, std::string> parseArguments(const int argc, char* argv[]) noexcept
456 {
457 Config config;
458 bool script_file_set = false;
459
460 if (argc < 2)
461 {
462 showHelp(argv[0]);
463 return std::unexpected("No arguments provided.");
464 }
465
466 for (int i = 1; i < argc; ++i)
467 {
468 const std::string arg = argv[i];
469 const auto require_value = [&](const std::string& option) -> std::expected<std::string, std::string>
470 {
471 if (i + 1 >= argc)
472 {
473 return std::unexpected(option + " requires a value");
474 }
475 ++i;
476 return std::string{argv[i]};
477 };
478
RealType a

◆ projectSimulationMemory()

SimulationMemoryProjection core::projectSimulationMemory ( const World world)

Projects startup memory and rendered-output sizes for a simulation world.

Parameters
worldThe simulation world to inspect.
Returns
A populated memory projection for the current simulation parameters.

Definition at line 385 of file memory_projection.cpp.

386 {
388 projection.duration_seconds = std::max<RealType>(0.0, params::endTime() - params::startTime());
389 projection.oversample_ratio = params::oversampleRatio();
390 projection.simulation_sample_rate_hz = params::rate() * static_cast<RealType>(projection.oversample_ratio);
391
392 bool sample_count_overflowed = false;
393 projection.streaming_sample_count = countSamplesForDuration(
394 projection.duration_seconds, projection.simulation_sample_rate_hz, sample_count_overflowed);
395
397 bool phase_noise_count_overflowed = false;
398 projection.phase_noise_sample_count =
400 projection.simulation_sample_rate_hz, phase_noise_count_overflowed);
401 if (projection.phase_noise_sample_count != max_uint64)
402 {
403 ++projection.phase_noise_sample_count;
404 }
406 {
407 projection.phase_noise_sample_count = max_uint64;
408 }
409
410 const auto timings = collectCwPhaseNoiseTimings(world);
411 projection.phase_noise_timing_count = static_cast<std::uint64_t>(timings.size());
412 for (const auto& timing : timings)
413 {
414 if (timing && timing->isEnabled())
415 {
416 ++projection.enabled_phase_noise_timing_count;
417 }
418 }
419
420 projection.phase_noise_lookup =
421 multiplyBytes(projection.phase_noise_sample_count,
422 projection.enabled_phase_noise_timing_count * static_cast<std::uint64_t>(sizeof(RealType)),
424
425 for (const auto& receiver_ptr : world.getReceivers())
426 {
427 const auto& receiver = *receiver_ptr;
429 {
431 continue;
432 }
433
434 if (receiver.getMode() == OperationMode::PULSED_MODE)
435 {
437 }
438 }
439
440 projection.rendered_hdf5_payload =
441 multiplyBytes(projection.rendered_hdf5_sample_count, 2ULL * static_cast<std::uint64_t>(sizeof(RealType)));
442
443 projection.current_resident_set = currentResidentSetBytes();
444 if (projection.current_resident_set.has_value())
445 {
446 projection.resident_baseline = ByteProjection{.bytes = *projection.current_resident_set};
447 projection.projected_total_footprint =
448 addBytes(addBytes(addBytes(projection.phase_noise_lookup, projection.streaming_iq_buffers),
449 projection.rendered_hdf5_payload),
450 *projection.resident_baseline);
451 }
452
453 return projection;
454 }
RealType earliestPhaseNoiseLookupStart() const
Finds the earliest simulation time that can require CW phase-noise samples.
Definition world.cpp:209
void addPulsedReceiverProjection(SimulationMemoryProjection &projection, const radar::Receiver &receiver)
void addStreamingReceiverProjection(SimulationMemoryProjection &projection, const radar::Receiver &receiver, const bool sample_count_overflowed)
std::vector< std::shared_ptr< timing::Timing > > collectCwPhaseNoiseTimings(const World &world)
Collects unique timing sources used by CW/FMCW transmitters and receivers.
RealType endTime() noexcept
Get the end time for the simulation.
Definition parameters.h:109
RealType rate() noexcept
Get the rendering sample rate.
Definition parameters.h:121
RealType startTime() noexcept
Get the start time for the simulation.
Definition parameters.h:103
unsigned oversampleRatio() noexcept
Get the oversampling ratio.
Definition parameters.h:151
Captures startup memory and rendered-output projections for a simulation.

References addPulsedReceiverProjection(), addStreamingReceiverProjection(), core::ByteProjection::bytes, collectCwPhaseNoiseTimings(), core::World::earliestPhaseNoiseLookupStart(), params::endTime(), core::World::getReceivers(), max, params::oversampleRatio(), params::rate(), receiver, and params::startTime().

Referenced by fers_get_memory_projection_json(), and logSimulationMemoryProjection().

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

◆ resolveKmlOutputPath()

std::filesystem::path core::resolveKmlOutputPath ( const std::string &  script_file,
const std::filesystem::path &  final_output_dir,
const std::optional< std::string > &  kml_file 
)
noexcept

Resolves the KML output file path from CLI arguments and output directory.

Definition at line 25 of file cli_paths.cpp.

28 {
29 if (kml_file && !kml_file->empty())
30 {
31 std::filesystem::path provided_kml_path(*kml_file);
32 if (provided_kml_path.has_parent_path() || provided_kml_path.is_absolute())
33 {
34 return provided_kml_path;
35 }
36
38 }
39
40 std::filesystem::path kml_output_path = final_output_dir / std::filesystem::path(script_file).filename();
41 kml_output_path.replace_extension(".kml");
42 return kml_output_path;
43 }

◆ resolveOutputDir()

std::filesystem::path core::resolveOutputDir ( const std::string &  script_file,
const std::optional< std::string > &  output_dir 
)
noexcept

Resolves the final simulation output directory from CLI arguments.

Definition at line 8 of file cli_paths.cpp.

10 {
11 if (output_dir)
12 {
13 return std::filesystem::path(*output_dir);
14 }
15
16 std::filesystem::path default_out_dir = std::filesystem::path(script_file).parent_path();
17 if (default_out_dir.empty())
18 {
19 default_out_dir = ".";
20 }
21
22 return default_out_dir;
23 }

◆ runEventDrivenSim()

OutputMetadata core::runEventDrivenSim ( World world,
pool::ThreadPool pool,
const std::function< void(const std::string &, int, int)> &  progress_callback,
const std::string &  output_dir,
const OutputConfig output_config = OutputConfig{},
std::function< bool()>  cancel_callback = nullptr,
bool cancelled = nullptr,
ReceiverOutputTelemetryCallback  telemetry_callback = nullptr 
)

Runs the unified, event-driven radar simulation.

This function is the core entry point of the simulator. It advances time by processing events from a global priority queue. It handles both pulsed and continuous-wave (CW) physics, dispatching finalization tasks to worker threads for asynchronous processing.

Parameters
worldA pointer to the simulation world containing all entities and state.
poolA reference to the thread pool for executing tasks.
progress_callbackAn optional callback function for reporting progress.
output_dirOutput directory for the simulation files.

Definition at line 2071 of file sim_threading.cpp.

2076 {
2077 if (cancelled != nullptr)
2078 {
2079 *cancelled = false;
2080 }
2081 auto reporter = std::make_shared<ProgressReporter>(progress_callback);
2082 auto metadata_collector = std::make_shared<OutputMetadataCollector>(output_dir);
2083 std::unique_ptr<ReceiverOutputSink> output_sink;
2084 if (isVita49Enabled(output_config))
2085 {
2087 output_sink->initializeRun(output_config, params::params.simulation_name);
2088 }
2089 else
2090 {
2091 output_sink = serial::makeHdf5OutputSink(output_dir, metadata_collector);
2092 output_sink->initializeRun(output_config, params::params.simulation_name);
2093 }
2094
2095 SimulationEngine engine(world, pool, reporter, output_dir, metadata_collector, output_sink.get(),
2096 std::move(cancel_callback), isVita49Enabled(output_config));
2097 engine.run();
2098 if (cancelled != nullptr)
2099 {
2100 *cancelled = engine.cancelled();
2101 }
2103 {
2104 LOG(Level::INFO, "Waiting for VITA output stream drain...");
2105 reporter->report("Waiting for VITA output stream drain...", 100, 100);
2106 }
2107 const auto stats = output_sink->finalize();
2108 reporter->report(engine.cancelled() ? "Simulation cancelled" : "Simulation complete", 100, 100);
2109 LOG(Level::INFO, "Event-driven simulation loop finished.");
2110 auto metadata = metadata_collector->snapshot();
2111 if (output_sink)
2112 {
2114 {
2116 if (stats.epoch_unix_nanoseconds.has_value())
2117 {
2118 vita49_metadata.epoch_unix_nanoseconds = stats.epoch_unix_nanoseconds;
2119 }
2120 for (const auto& stream : stats.streams)
2121 {
2122 vita49_metadata.streams.push_back(streamStatsToMetadata(stream));
2123 }
2124 metadata.vita49 = std::move(vita49_metadata);
2125 }
2126 }
2127 return metadata;
2128 }
bool isVita49Enabled(const OutputConfig &config) noexcept
Vita49OutputMetadata vita49MetadataFromConfig(const Vita49OutputConfig &config)
Builds the static VITA metadata section from runtime output configuration.
Parameters params
Global simulation parameter state.
Definition parameters.h:85
std::unique_ptr< core::ReceiverOutputSink > makeVita49OutputSink(core::ReceiverOutputTelemetryCallback telemetry_callback)
std::unique_ptr< core::ReceiverOutputSink > makeHdf5OutputSink(std::string output_dir, std::shared_ptr< core::OutputMetadataCollector > metadata_collector)

References isVita49Enabled(), LOG, serial::makeHdf5OutputSink(), serial::vita49::makeVita49OutputSink(), max, params::params, and vita49MetadataFromConfig().

+ Here is the call graph for this function:

◆ showHelp()

void core::showHelp ( const char programName)
noexcept

Displays the help message.

Parameters
programNameThe name of the program.

Definition at line 400 of file arg_parser.cpp.

401 {
402 const char* version = fers_get_version();
403
404 std::cout << "/------------------------------------------------\\\n"
405 << "| FERS - The Flexible Extensible Radar Simulator |\n"
406 << std::format("| Version {:<40}|\n", version)
407 << "\\------------------------------------------------/\n"
408 << "Usage: " << programName << R"( <scriptfile> [options]
409
410Options:
const char * fers_get_version(void)
Returns the library version string.
Definition api.cpp:377

References fers_get_version().

+ Here is the call graph for this function:

◆ showVersion()

void core::showVersion ( )
noexcept

Displays the version information.

Definition at line 412 of file arg_parser.cpp.

◆ toString()

std::string core::toString ( const EventType  type)

Converts an EventType enum to its string representation.

Parameters
typeThe event type.
Returns
A string representing the event type.

Definition at line 74 of file sim_events.h.

75 {
76 switch (type)
77 {
78 case EventType::TX_PULSED_START:
79 return "TxPulsedStart";
80 case EventType::RX_PULSED_WINDOW_START:
81 return "RxPulsedWindowStart";
82 case EventType::RX_PULSED_WINDOW_END:
83 return "RxPulsedWindowEnd";
84 case EventType::TX_STREAMING_START:
85 return "TxStreamingStart";
86 case EventType::TX_STREAMING_END:
87 return "TxStreamingEnd";
88 case EventType::RX_STREAMING_START:
89 return "RxStreamingStart";
90 case EventType::RX_STREAMING_END:
91 return "RxStreamingEnd";
92 default:
93 return "UnknownEvent";
94 }
95 }

References RX_PULSED_WINDOW_END, RX_PULSED_WINDOW_START, RX_STREAMING_END, RX_STREAMING_START, TX_PULSED_START, TX_STREAMING_END, and TX_STREAMING_START.

Referenced by core::World::dumpEventQueue().

+ Here is the caller graph for this function:

◆ vita49MetadataFromConfig()

Vita49OutputMetadata core::vita49MetadataFromConfig ( const Vita49OutputConfig config)

Builds the static VITA metadata section from runtime output configuration.

Definition at line 438 of file output_metadata.cpp.

439 {
441 .endpoint_port = config.port,
442 .epoch_unix_nanoseconds = config.epoch_unix_nanoseconds,
443 .adc_fullscale = config.adc_fullscale,
444 .max_udp_payload = config.max_udp_payload,
445 .queue_depth = config.queue_depth};
446 }
Metadata for the VITA 49.2 UDP output backend.
std::string endpoint_host
Destination host.

References core::Vita49OutputMetadata::endpoint_host, max, and vita49MetadataFromConfig().

Referenced by runEventDrivenSim(), and vita49MetadataFromConfig().

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