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;
276 for (
auto&
tgt : _targets)
277 if (
tgt->getId() ==
id)
285 for (
auto& t : _targets)
287 if (t->getId() ==
id)
293 _targets.push_back(std::move(
target));
304 if (
auto it = _antennas.find(
id);
it != _antennas.end())
317 for (
auto&
tx : _transmitters)
321 for (
auto&
rx : _receivers)
329 const SimId id = waveform->getId();
331 const std::string
new_name = waveform->getName();
336 if (
auto it = _waveforms.find(
id);
it != _waveforms.end())
340 _waveform_ids_by_name.erase(
old_owned->getName());
342 it->second = std::move(waveform);
347 _waveforms[
id] = std::move(waveform);
352 for (
auto&
tx : _transmitters)
363 std::unique_ptr<PrototypeTiming>
old_owned;
366 if (
auto it = _timings.find(
id);
it != _timings.end())
377 std::unordered_map<const timing::Timing*, std::shared_ptr<timing::Timing>>
refreshed_instances;
400 for (
auto&
tx : _transmitters)
403 for (
auto&
rx : _receivers)
411 _transmitters.clear();
412 _transmitters_by_name.clear();
416 _waveform_ids_by_name.clear();
420 _simulation_state = {};
427 _platforms.swap(
other._platforms);
428 _transmitters.swap(
other._transmitters);
429 _receivers.swap(
other._receivers);
430 _targets.swap(
other._targets);
431 _waveforms.swap(
other._waveforms);
432 _waveform_ids_by_name.swap(
other._waveform_ids_by_name);
433 _transmitters_by_name.swap(
other._transmitters_by_name);
434 _antennas.swap(
other._antennas);
435 _timings.swap(
other._timings);
436 _event_queue.swap(
other._event_queue);
437 swap(_simulation_state,
other._simulation_state);
450 for (
const auto&
receiver : _receivers)
492 pushStreamingTransmitterEvents(
transmitter, start, end);
540 pushStreamingReceiverEvents(
receiver, start, end);
555 for (
const auto&
rx_ptr : _receivers)
558 rx.clearResolvedDechirpSources();
559 if (!
rx.isDechirpEnabled())
565 throw std::runtime_error(
"Receiver '" +
rx.getName() +
"' enables dechirping outside FMCW mode.");
569 std::vector<ActiveStreamingSource>
sources;
570 const std::string
owner =
"Receiver '" +
rx.getName() +
"'";
573 case Receiver::DechirpReferenceSource::Attached:
575 const auto*
const tx =
dynamic_cast<const Transmitter*
>(
rx.getAttached());
582 case Receiver::DechirpReferenceSource::Transmitter:
591 case Receiver::DechirpReferenceSource::Custom:
596 throw std::runtime_error(
owner +
" custom dechirp reference waveform '" +
reference.name +
597 "' must be a top-level FMCW waveform.");
604 case Receiver::DechirpReferenceSource::None:
605 throw std::runtime_error(
owner +
" enables dechirping without a dechirp reference.");
610 throw std::runtime_error(
owner +
" dechirp reference has no active LO segments in the simulation.");
613 {
return lhs.segment_start <
rhs.segment_start; });
615 rx.setResolvedDechirpSources(std::move(
sources));
621 if (_event_queue.empty())
623 return "Event Queue is empty.\n";
626 std::stringstream
ss;
627 ss << std::fixed << std::setprecision(6);
629 const std::string
separator =
"--------------------------------------------------------------------";
630 const std::string
title =
"| Event Queue Contents (" + std::to_string(_event_queue.size()) +
" events)";
631 if (
separator.size() >
static_cast<std::size_t
>(std::numeric_limits<int>::max()))
633 throw std::runtime_error(
"Separator width exceeds stream formatting limits.");
640 <<
"| " << std::left << std::setw(12) <<
"Timestamp" <<
" | " << std::setw(21) <<
"Event Type" <<
" | "
641 << std::setw(25) <<
"Source Object" <<
" |\n"
651 ss <<
"| " << std::right << std::setw(12) << timestamp <<
" | " << std::left << std::setw(21)
652 <<
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.
@ SFCW_MODE
The component operates in a stepped-frequency CW streaming mode.
@ 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.