21#include <unordered_map>
47 std::vector<ActiveStreamingSource>
sources;
48 if (
tx->getSchedule().empty())
51 if (source.segment_start < source.segment_end)
58 for (
const auto&
period :
tx->getSchedule())
61 if (source.segment_start < source.segment_end && source.segment_end >
params::startTime())
72 std::vector<ActiveStreamingSource>
sources;
73 if (
rx->getSchedule().empty())
76 if (source.segment_start < source.segment_end)
83 for (
const auto&
period :
rx->getSchedule())
87 if (source.segment_start < source.segment_end && source.segment_end >
params::startTime())
99 throw std::runtime_error(
owner +
" references a missing dechirp transmitter.");
102 !
tx->getSignal()->isFmcwFamily())
104 throw std::runtime_error(
owner +
" dechirp reference transmitter '" +
tx->getName() +
105 "' must be an FMCW transmitter with an FMCW waveform.");
114 _transmitters_by_name[
trans->getName()] =
trans.get();
115 _transmitters.push_back(std::move(
trans));
124 const SimId id = waveform->getId();
125 if (_waveforms.contains(
id))
127 throw std::runtime_error(
"A waveform with the ID " + std::to_string(
id) +
" already exists.");
129 _waveform_ids_by_name[waveform->getName()] =
id;
130 _waveforms[
id] = std::move(waveform);
136 if (_antennas.contains(
id))
138 throw std::runtime_error(
"An antenna with the ID " + std::to_string(
id) +
" already exists.");
146 if (_timings.contains(
id))
148 throw std::runtime_error(
"A timing source with the ID " + std::to_string(
id) +
" already exists.");
155 const auto it = _waveforms.find(
id);
156 return it != _waveforms.end() ?
it->second.get() :
nullptr;
161 const auto it = _antennas.find(
id);
162 return it != _antennas.end() ?
it->second.get() :
nullptr;
167 const auto it = _timings.find(
id);
168 return it != _timings.end() ?
it->second.get() :
nullptr;
173 for (
auto&
p : _platforms)
175 if (
p->getId() ==
id)
183 for (
auto&
tx : _transmitters)
184 if (
tx->getId() ==
id)
191 const auto it = _transmitters_by_name.find(name);
192 return it != _transmitters_by_name.end() ?
it->second :
nullptr;
197 for (
auto&
rx : _receivers)
198 if (
rx->getId() ==
id)
205 const auto it = _waveform_ids_by_name.find(name);
206 return it != _waveform_ids_by_name.end() ?
findWaveform(
it->second) :
nullptr;
275 for (
auto&
tgt : _targets)
276 if (
tgt->getId() ==
id)
284 for (
auto& t : _targets)
286 if (t->getId() ==
id)
292 _targets.push_back(std::move(
target));
303 if (
auto it = _antennas.find(
id);
it != _antennas.end())
316 for (
auto&
tx : _transmitters)
320 for (
auto&
rx : _receivers)
328 const SimId id = waveform->getId();
330 const std::string
new_name = waveform->getName();
335 if (
auto it = _waveforms.find(
id);
it != _waveforms.end())
339 _waveform_ids_by_name.erase(
old_owned->getName());
341 it->second = std::move(waveform);
346 _waveforms[
id] = std::move(waveform);
351 for (
auto&
tx : _transmitters)
362 std::unique_ptr<PrototypeTiming>
old_owned;
365 if (
auto it = _timings.find(
id);
it != _timings.end())
376 std::unordered_map<const timing::Timing*, std::shared_ptr<timing::Timing>>
refreshed_instances;
399 for (
auto&
tx : _transmitters)
402 for (
auto&
rx : _receivers)
410 _transmitters.clear();
411 _transmitters_by_name.clear();
415 _waveform_ids_by_name.clear();
419 _simulation_state = {};
426 _platforms.swap(
other._platforms);
427 _transmitters.swap(
other._transmitters);
428 _receivers.swap(
other._receivers);
429 _targets.swap(
other._targets);
430 _waveforms.swap(
other._waveforms);
431 _waveform_ids_by_name.swap(
other._waveform_ids_by_name);
432 _transmitters_by_name.swap(
other._transmitters_by_name);
433 _antennas.swap(
other._antennas);
434 _timings.swap(
other._timings);
435 _event_queue.swap(
other._event_queue);
436 swap(_simulation_state,
other._simulation_state);
449 for (
const auto&
receiver : _receivers)
491 pushStreamingTransmitterEvents(
transmitter, start, end);
539 pushStreamingReceiverEvents(
receiver, start, end);
554 for (
const auto&
rx_ptr : _receivers)
557 rx.clearResolvedDechirpSources();
558 if (!
rx.isDechirpEnabled())
564 throw std::runtime_error(
"Receiver '" +
rx.getName() +
"' enables dechirping outside FMCW mode.");
568 std::vector<ActiveStreamingSource>
sources;
569 const std::string
owner =
"Receiver '" +
rx.getName() +
"'";
572 case Receiver::DechirpReferenceSource::Attached:
574 const auto*
const tx =
dynamic_cast<const Transmitter*
>(
rx.getAttached());
581 case Receiver::DechirpReferenceSource::Transmitter:
590 case Receiver::DechirpReferenceSource::Custom:
595 throw std::runtime_error(
owner +
" custom dechirp reference waveform '" +
reference.name +
596 "' must be a top-level FMCW waveform.");
603 case Receiver::DechirpReferenceSource::None:
604 throw std::runtime_error(
owner +
" enables dechirping without a dechirp reference.");
609 throw std::runtime_error(
owner +
" dechirp reference has no active LO segments in the simulation.");
612 {
return lhs.segment_start <
rhs.segment_start; });
614 rx.setResolvedDechirpSources(std::move(
sources));
620 if (_event_queue.empty())
622 return "Event Queue is empty.\n";
625 std::stringstream
ss;
626 ss << std::fixed << std::setprecision(6);
628 const std::string
separator =
"--------------------------------------------------------------------";
629 const std::string
title =
"| Event Queue Contents (" + std::to_string(_event_queue.size()) +
" events)";
630 if (
separator.size() >
static_cast<std::size_t
>(std::numeric_limits<int>::max()))
632 throw std::runtime_error(
"Separator width exceeds stream formatting limits.");
639 <<
"| " << std::left << std::setw(12) <<
"Timestamp" <<
" | " << std::setw(21) <<
"Event Type" <<
" | "
640 << std::setw(25) <<
"Source Object" <<
" |\n"
650 ss <<
"| " << std::right << std::setw(12) << timestamp <<
" | " << std::left << std::setw(21)
651 <<
toString(
event_type) <<
" | " << std::left << std::setw(25) << source_object->getName() <<
" |\n";
Header file defining various types of antennas and their gain patterns.
const Transmitter & transmitter
const Receiver & receiver
Abstract base class representing an antenna.
The World class manages the simulator environment.
void scheduleInitialEvents()
Populates the event queue with the initial events for the simulation.
void add(std::unique_ptr< radar::Platform > plat) noexcept
Adds a radar platform to the simulation world.
void replace(std::unique_ptr< radar::Target > target)
Replaces an existing target, updating internal pointers.
fers_signal::RadarSignal * findWaveform(const SimId id)
Finds a radar signal by ID.
radar::Target * findTarget(const SimId id)
Finds a target by ID.
fers_signal::RadarSignal * findWaveformByName(const std::string &name)
Finds a waveform by name.
radar::Receiver * findReceiver(const SimId id)
Finds a receiver by ID.
radar::Transmitter * findTransmitter(const SimId id)
Finds a transmitter by ID.
void clear() noexcept
Clears all objects and assets from the simulation world.
void resolveReceiverDechirpReferences()
Resolves and validates receiver FMCW dechirp references after all components are loaded.
timing::PrototypeTiming * findTiming(const SimId id)
Finds a timing source by ID.
antenna::Antenna * findAntenna(const SimId id)
Finds an antenna by ID.
void swap(World &other) noexcept
Exchanges all owned world state with another world.
std::string dumpEventQueue() const
Dumps the current state of the event queue to a string for debugging.
radar::Platform * findPlatform(const SimId id)
Finds a platform by ID.
radar::Transmitter * findTransmitterByName(const std::string &name)
Finds a transmitter by name.
RealType earliestPhaseNoiseLookupStart() const
Finds the earliest simulation time that can require CW phase-noise samples.
Class representing a radar signal with associated properties.
SimId getId() const noexcept
Gets the unique ID of the radar signal.
const std::string & getName() const noexcept
Gets the name of the radar signal.
bool isFmcwFamily() const noexcept
Returns true when this signal belongs to the FMCW waveform family.
Manages radar signal reception and response processing.
const std::vector< SchedulePeriod > & getSchedule() const noexcept
Retrieves the list of active reception periods.
RealType getWindowStart(unsigned window) const
Retrieves the start time of a specific radar window.
std::optional< RealType > getNextWindowTime(RealType time) const
Determines the next valid window start time at or after the given time.
OperationMode getMode() const noexcept
Gets the operational mode of the receiver.
Base class for radar targets.
Represents a radar transmitter system.
std::optional< RealType > getNextPulseTime(RealType time) const
Determines the valid simulation time for a pulse at or after the given time.
const std::vector< SchedulePeriod > & getSchedule() const noexcept
Retrieves the list of active transmission periods.
OperationMode getMode() const noexcept
Gets the operational mode of the transmitter.
Manages timing properties such as frequency, offsets, and synchronization.
Represents a timing source for simulation.
double RealType
Type for real numbers.
ActiveStreamingSource 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.
std::string toString(const EventType type)
Converts an EventType enum to its string representation.
@ RX_PULSED_WINDOW_START
A pulsed receiver opens 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.
ActiveStreamingSource 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.
RealType endTime() noexcept
Get the end time for the simulation.
RealType startTime() noexcept
Get the start time for the simulation.
@ PULSED_MODE
The component operates in a pulsed mode.
@ CW_MODE
The component operates in a continuous-wave mode.
@ FMCW_MODE
The component operates in an FMCW streaming mode.
Defines the Parameters struct and provides methods for managing simulation parameters.
Header file for the PrototypeTiming class.
Defines the Radar class and associated functionality.
Classes for handling radar waveforms and signals.
Defines the core structures for the event-driven simulation engine.
uint64_t SimId
64-bit Unique Simulation ID.
Cached description of an active streaming transmitter segment.
RealType segment_end
Segment end time in seconds.
Timing source for simulation objects.
Header file for the World class in the simulator.