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 , FileCw ,
  FileFmcw , 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 197 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 
FileCw 
FileFmcw 
Sfcw 

Definition at line 34 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 313 of file simulation_state.cpp.

315 {
317 if (!first_index.has_value())
318 {
319 return 0;
320 }
321
322 const RealType clipped_end = std::min(active_end, source.segment_end);
323 const RealType first_start = source.segment_start + static_cast<RealType>(*first_index) * source.chirp_period;
325 if (!source.chirp_count.has_value())
326 {
327 return starts_in_interval;
328 }
329
330 const auto configured = static_cast<std::uint64_t>(*source.chirp_count);
331 return std::min(starts_in_interval, configured - *first_index);
332 }
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 345 of file simulation_state.cpp.

347 {
349 if (!first_index.has_value())
350 {
351 return 0;
352 }
353
354 const RealType clipped_end = std::min(active_end, source.segment_end);
355 const RealType first_start =
356 source.segment_start + static_cast<RealType>(*first_index) * source.triangle_period;
358 if (!source.triangle_count.has_value())
359 {
360 return starts_in_interval;
361 }
362
363 const auto configured = static_cast<std::uint64_t>(*source.triangle_count);
364 return std::min(starts_in_interval, configured - *first_index);
365 }
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 378 of file simulation_state.cpp.

380 {
382 if (!first_index.has_value())
383 {
384 return 0;
385 }
386
387 const RealType clipped_end = std::min(active_end, source.segment_end);
388 const RealType first_start =
389 source.segment_start + static_cast<RealType>(*first_index) * source.sfcw_step_period;
391 if (!source.sfcw_sweep_count.has_value())
392 {
393 return starts_in_interval;
394 }
395
396 const auto configured = static_cast<std::uint64_t>(*source.sfcw_sweep_count) * source.sfcw_step_count;
397 return std::min(starts_in_interval, configured - *first_index);
398 }
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 302 of file simulation_state.cpp.

304 {
306 if (!first_index.has_value())
307 {
308 return std::nullopt;
309 }
310 return source.segment_start + static_cast<RealType>(*first_index) * source.chirp_period;
311 }

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 334 of file simulation_state.cpp.

336 {
338 if (!first_index.has_value())
339 {
340 return std::nullopt;
341 }
342 return source.segment_start + static_cast<RealType>(*first_index) * source.triangle_period;
343 }

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 367 of file simulation_state.cpp.

369 {
371 if (!first_index.has_value())
372 {
373 return std::nullopt;
374 }
375 return source.segment_start + static_cast<RealType>(*first_index) * source.sfcw_step_period;
376 }

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 259 of file simulation_state.cpp.

261 {
262 ActiveStreamingSource source{};
263 source.transmitter = tx;
264 source.segment_start = segment_start;
265 source.segment_end = segment_end;
266 if (tx == nullptr)
267 {
268 return source;
269 }
270
271 const auto* const signal = tx->getSignal();
272 if (signal == nullptr)
273 {
274 return source;
275 }
276
277 const RealType raw_segment_end = segment_end;
278 populateWaveformCache(source, signal, segment_start);
279 if (source.kind == StreamingWaveformKind::FmcwTriangle &&
281 {
282 const auto emitted_triangles = static_cast<std::uint64_t>(
283 std::max<RealType>(0.0, (source.segment_end - segment_start) / source.triangle_period));
285 "FMCW triangle transmitter '{}' segment [{}, {}] emits {} complete triangles and drops {} s of "
286 "leftover active time.",
287 tx->getName(), segment_start, raw_segment_end, emitted_triangles, raw_segment_end - source.segment_end);
288 }
289 return source;
290 }
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 292 of file simulation_state.cpp.

294 {
295 ActiveStreamingSource source{};
296 source.segment_start = segment_start;
297 source.segment_end = segment_end;
298 populateWaveformCache(source, signal, segment_start);
299 return source;
300 }

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 443 of file output_metadata.cpp.

444 {
445 return fileToJson(metadata).dump(2);
446 }

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 448 of file output_metadata.cpp.

448{ 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 :
431 <scriptfile> Path to the simulation script file (XML)
432
433Example:
434 )" << programName
435 << R"( simulation.fersxml --out-dir=./results --log-level=DEBUG -n=4
436
438Make sure the script file follows the correct format to avoid errors.
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 2093 of file sim_threading.cpp.

2098 {
2099 if (cancelled != nullptr)
2100 {
2101 *cancelled = false;
2102 }
2103 auto reporter = std::make_shared<ProgressReporter>(progress_callback);
2104 auto metadata_collector = std::make_shared<OutputMetadataCollector>(output_dir);
2105 std::unique_ptr<ReceiverOutputSink> output_sink;
2106 if (isVita49Enabled(output_config))
2107 {
2109 output_sink->initializeRun(output_config, params::params.simulation_name);
2110 }
2111 else
2112 {
2113 output_sink = serial::makeHdf5OutputSink(output_dir, metadata_collector);
2114 output_sink->initializeRun(output_config, params::params.simulation_name);
2115 }
2116
2117 SimulationEngine engine(world, pool, reporter, output_dir, metadata_collector, output_sink.get(),
2118 std::move(cancel_callback), isVita49Enabled(output_config));
2119 engine.run();
2120 if (cancelled != nullptr)
2121 {
2122 *cancelled = engine.cancelled();
2123 }
2125 {
2126 LOG(Level::INFO, "Waiting for VITA output stream drain...");
2127 reporter->report("Waiting for VITA output stream drain...", 100, 100);
2128 }
2129 const auto stats = output_sink->finalize();
2130 reporter->report(engine.cancelled() ? "Simulation cancelled" : "Simulation complete", 100, 100);
2131 LOG(Level::INFO, "Event-driven simulation loop finished.");
2132 auto metadata = metadata_collector->snapshot();
2133 if (output_sink)
2134 {
2136 {
2138 if (stats.epoch_unix_nanoseconds.has_value())
2139 {
2140 vita49_metadata.epoch_unix_nanoseconds = stats.epoch_unix_nanoseconds;
2141 }
2142 for (const auto& stream : stats.streams)
2143 {
2144 vita49_metadata.streams.push_back(streamStatsToMetadata(stream));
2145 }
2146 metadata.vita49 = std::move(vita49_metadata);
2147 }
2148 }
2149 return metadata;
2150 }
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:378

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 450 of file output_metadata.cpp.

451 {
453 .endpoint_port = config.port,
454 .epoch_unix_nanoseconds = config.epoch_unix_nanoseconds,
455 .adc_fullscale = config.adc_fullscale,
456 .max_udp_payload = config.max_udp_payload,
457 .queue_depth = config.queue_depth};
458 }
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: