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...
 
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 }
 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.
 
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 173 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 

Definition at line 32 of file simulation_state.h.

Function Documentation

◆ addPulsedReceiverProjection()

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

Definition at line 365 of file memory_projection.cpp.

366 {
367 ++projection.pulsed_receiver_count;
368 bool window_count_overflowed = false;
370 projection.pulsed_window_count = addBytes({.bytes = projection.pulsed_window_count},
371 {.bytes = windows, .overflowed = window_count_overflowed})
372 .bytes;
373
376 receiver.getWindowLength(), projection.simulation_sample_rate_hz, pulsed_sample_count_overflowed);
378 const auto rendered_samples =
380 projection.rendered_hdf5_sample_count =
381 addBytes({.bytes = projection.rendered_hdf5_sample_count}, rendered_samples).bytes;
382 }
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 340 of file memory_projection.cpp.

342 {
343 ++projection.streaming_receiver_count;
344 bool if_count_overflowed = false;
345 const auto if_sample_rate = receiver.getIfSampleRate();
346 const bool if_rate_dechirped = receiver.isDechirpEnabled() && if_sample_rate.has_value();
348 ? countSamplesForDuration(projection.duration_seconds, if_sample_rate.value_or(0.0), if_count_overflowed)
349 : std::uint64_t{0};
352 : (receiver.isDechirpEnabled() ? projection.streaming_sample_count
353 : downsampledSampleCount(projection.streaming_sample_count));
354 projection.rendered_hdf5_sample_count =
355 addBytes({.bytes = projection.rendered_hdf5_sample_count},
357 .bytes;
358 const auto resident_samples = if_rate_dechirped ? if_sample_count : projection.streaming_sample_count;
359 projection.streaming_iq_buffers =
360 addBytes(projection.streaming_iq_buffers,
361 multiplyBytes(resident_samples, static_cast<std::uint64_t>(sizeof(ComplexType)),
363 }
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 309 of file memory_projection.cpp.

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

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

251 {
253 if (!first_index.has_value())
254 {
255 return 0;
256 }
257
258 const RealType clipped_end = std::min(active_end, source.segment_end);
259 const RealType first_start = source.segment_start + static_cast<RealType>(*first_index) * source.chirp_period;
261 if (!source.chirp_count.has_value())
262 {
263 return starts_in_interval;
264 }
265
266 const auto configured = static_cast<std::uint64_t>(*source.chirp_count);
267 return std::min(starts_in_interval, configured - *first_index);
268 }
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 281 of file simulation_state.cpp.

283 {
285 if (!first_index.has_value())
286 {
287 return 0;
288 }
289
290 const RealType clipped_end = std::min(active_end, source.segment_end);
291 const RealType first_start =
292 source.segment_start + static_cast<RealType>(*first_index) * source.triangle_period;
294 if (!source.triangle_count.has_value())
295 {
296 return starts_in_interval;
297 }
298
299 const auto configured = static_cast<std::uint64_t>(*source.triangle_count);
300 return std::min(starts_in_interval, configured - *first_index);
301 }
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.

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

240 {
242 if (!first_index.has_value())
243 {
244 return std::nullopt;
245 }
246 return source.segment_start + static_cast<RealType>(*first_index) * source.chirp_period;
247 }

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

272 {
274 if (!first_index.has_value())
275 {
276 return std::nullopt;
277 }
278 return source.segment_start + static_cast<RealType>(*first_index) * source.triangle_period;
279 }

References max, core::ActiveStreamingSource::segment_start, and core::ActiveStreamingSource::triangle_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 455 of file memory_projection.cpp.

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

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 501 of file memory_projection.cpp.

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

197 {
198 ActiveStreamingSource source{};
199 source.transmitter = tx;
200 source.segment_start = segment_start;
201 source.segment_end = segment_end;
202 if (tx == nullptr)
203 {
204 return source;
205 }
206
207 const auto* const signal = tx->getSignal();
208 if (signal == nullptr)
209 {
210 return source;
211 }
212
213 const RealType raw_segment_end = segment_end;
214 populateWaveformCache(source, signal, segment_start);
215 if (source.kind == StreamingWaveformKind::FmcwTriangle &&
217 {
218 const auto emitted_triangles = static_cast<std::uint64_t>(
219 std::max<RealType>(0.0, (source.segment_end - segment_start) / source.triangle_period));
221 "FMCW triangle transmitter '{}' segment [{}, {}] emits {} complete triangles and drops {} s of "
222 "leftover active time.",
223 tx->getName(), segment_start, raw_segment_end, emitted_triangles, raw_segment_end - source.segment_end);
224 }
225 return source;
226 }
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 228 of file simulation_state.cpp.

230 {
231 ActiveStreamingSource source{};
232 source.segment_start = segment_start;
233 source.segment_end = segment_end;
234 populateWaveformCache(source, signal, segment_start);
235 return source;
236 }

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 472 of file memory_projection.cpp.

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

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

361 {
362 return fileToJson(metadata).dump(2);
363 }

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

365{ 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 384 of file memory_projection.cpp.

385 {
387 projection.duration_seconds = std::max<RealType>(0.0, params::endTime() - params::startTime());
388 projection.oversample_ratio = params::oversampleRatio();
389 projection.simulation_sample_rate_hz = params::rate() * static_cast<RealType>(projection.oversample_ratio);
390
391 bool sample_count_overflowed = false;
392 projection.streaming_sample_count = countSamplesForDuration(
393 projection.duration_seconds, projection.simulation_sample_rate_hz, sample_count_overflowed);
394
396 bool phase_noise_count_overflowed = false;
397 projection.phase_noise_sample_count =
399 projection.simulation_sample_rate_hz, phase_noise_count_overflowed);
400 if (projection.phase_noise_sample_count != max_uint64)
401 {
402 ++projection.phase_noise_sample_count;
403 }
405 {
406 projection.phase_noise_sample_count = max_uint64;
407 }
408
409 const auto timings = collectCwPhaseNoiseTimings(world);
410 projection.phase_noise_timing_count = static_cast<std::uint64_t>(timings.size());
411 for (const auto& timing : timings)
412 {
413 if (timing && timing->isEnabled())
414 {
415 ++projection.enabled_phase_noise_timing_count;
416 }
417 }
418
419 projection.phase_noise_lookup =
420 multiplyBytes(projection.phase_noise_sample_count,
421 projection.enabled_phase_noise_timing_count * static_cast<std::uint64_t>(sizeof(RealType)),
423
424 for (const auto& receiver_ptr : world.getReceivers())
425 {
426 const auto& receiver = *receiver_ptr;
428 {
430 continue;
431 }
432
433 if (receiver.getMode() == OperationMode::PULSED_MODE)
434 {
436 }
437 }
438
439 projection.rendered_hdf5_payload =
440 multiplyBytes(projection.rendered_hdf5_sample_count, 2ULL * static_cast<std::uint64_t>(sizeof(RealType)));
441
442 projection.current_resident_set = currentResidentSetBytes();
443 if (projection.current_resident_set.has_value())
444 {
445 projection.resident_baseline = ByteProjection{.bytes = *projection.current_resident_set};
446 projection.projected_total_footprint =
447 addBytes(addBytes(addBytes(projection.phase_noise_lookup, projection.streaming_iq_buffers),
448 projection.rendered_hdf5_payload),
449 *projection.resident_baseline);
450 }
451
452 return projection;
453 }
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 2009 of file sim_threading.cpp.

2014 {
2015 if (cancelled != nullptr)
2016 {
2017 *cancelled = false;
2018 }
2019 auto reporter = std::make_shared<ProgressReporter>(progress_callback);
2020 auto metadata_collector = std::make_shared<OutputMetadataCollector>(output_dir);
2021 std::unique_ptr<ReceiverOutputSink> output_sink;
2022 if (isVita49Enabled(output_config))
2023 {
2025 output_sink->initializeRun(output_config, params::params.simulation_name);
2026 }
2027 else
2028 {
2029 output_sink = serial::makeHdf5OutputSink(output_dir, metadata_collector);
2030 output_sink->initializeRun(output_config, params::params.simulation_name);
2031 }
2032
2033 SimulationEngine engine(world, pool, reporter, output_dir, metadata_collector, output_sink.get(),
2034 std::move(cancel_callback), isVita49Enabled(output_config));
2035 engine.run();
2036 if (cancelled != nullptr)
2037 {
2038 *cancelled = engine.cancelled();
2039 }
2041 {
2042 LOG(Level::INFO, "Waiting for VITA output stream drain...");
2043 reporter->report("Waiting for VITA output stream drain...", 100, 100);
2044 }
2045 const auto stats = output_sink->finalize();
2046 reporter->report(engine.cancelled() ? "Simulation cancelled" : "Simulation complete", 100, 100);
2047 LOG(Level::INFO, "Event-driven simulation loop finished.");
2048 auto metadata = metadata_collector->snapshot();
2049 if (output_sink)
2050 {
2052 {
2054 if (stats.epoch_unix_nanoseconds.has_value())
2055 {
2056 vita49_metadata.epoch_unix_nanoseconds = stats.epoch_unix_nanoseconds;
2057 }
2058 for (const auto& stream : stats.streams)
2059 {
2060 vita49_metadata.streams.push_back(streamStatsToMetadata(stream));
2061 }
2062 metadata.vita49 = std::move(vita49_metadata);
2063 }
2064 }
2065 return metadata;
2066 }
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 367 of file output_metadata.cpp.

368 {
370 .endpoint_port = config.port,
371 .epoch_unix_nanoseconds = config.epoch_unix_nanoseconds,
372 .adc_fullscale = config.adc_fullscale,
373 .max_udp_payload = config.max_udp_payload,
374 .queue_depth = config.queue_depth};
375 }
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: