45 std::string output_dir,
46 std::shared_ptr<OutputMetadataCollector> metadata_collector) :
47 _world(world), _pool(
pool), _reporter(std::move(reporter)), _metadata_collector(std::move(metadata_collector)),
48 _last_report_time(std::chrono::steady_clock::now()), _output_dir(std::move(output_dir))
56 _reporter->report(
"Initializing event-driven simulation...", 0, 100);
59 initializeFinalizers();
61 LOG(Level::INFO,
"Starting unified event-driven simulation loop.");
67 while (!event_queue.empty() && state.t_current <= end_time)
69 const Event event = event_queue.top();
74 state.t_current =
event.timestamp;
83 void SimulationEngine::initializeFinalizers()
85 for (
const auto& receiver_ptr : _world->getReceivers())
87 if (receiver_ptr->getMode() == OperationMode::PULSED_MODE)
90 &_world->
getTargets(), _reporter, _output_dir, _metadata_collector);
99 if (t_event <= t_current)
105 const auto start_index =
static_cast<size_t>(std::ceil((t_current -
params::startTime()) / dt_sim));
106 const auto end_index =
static_cast<size_t>(std::ceil((t_event -
params::startTime()) / dt_sim));
108 for (
size_t sample_index = start_index; sample_index < end_index; ++sample_index)
114 if (receiver_ptr->getMode() == OperationMode::CW_MODE && receiver_ptr->isActive())
117 receiver_ptr->setCwSample(sample_index, sample);
124 const std::vector<Transmitter*>& cw_sources)
const
127 for (
const auto& cw_source : cw_sources)
129 if (!rx->
checkFlag(Receiver::RecvFlag::FLAG_NODIRECT))
133 for (
const auto& target_ptr : _world->
getTargets())
171 void SimulationEngine::routeResponse(
Receiver* rx, std::unique_ptr<serial::Response> response)
const
177 if (rx->
getMode() == OperationMode::PULSED_MODE)
191 if (!rx_ptr->checkFlag(Receiver::RecvFlag::FLAG_NODIRECT))
195 for (
const auto& target_ptr : _world->
getTargets())
203 const RealType next_theoretical_time = t_event + 1.0 / tx->
getPrf();
204 if (
const auto next_pulse_opt = tx->
getNextPulseTime(next_theoretical_time);
225 .active_cw_sources = active_cw_transmitters};
245 std::erase(cw_txs, tx);
252 void SimulationEngine::updateProgress()
261 const int progress =
static_cast<int>(t_current / end_time * 100.0);
263 if (
const auto now = std::chrono::steady_clock::now();
264 progress != _last_reported_percent || now - _last_report_time >= std::chrono::milliseconds(100))
266 _reporter->report(std::format(
"Simulating... {:.2f}s / {:.2f}s", t_current, end_time), progress, 100);
267 _last_reported_percent = progress;
268 _last_report_time = now;
272 void SimulationEngine::shutdown()
274 LOG(Level::INFO,
"Main simulation loop finished. Waiting for finalization tasks...");
277 _reporter->report(
"Main simulation finished. Waiting for data export...", 100, 100);
280 for (
const auto& receiver_ptr : _world->getReceivers())
282 if (receiver_ptr->getMode() == OperationMode::CW_MODE)
285 _metadata_collector);
287 else if (receiver_ptr->getMode() == OperationMode::PULSED_MODE)
289 RenderingJob shutdown_job{};
290 shutdown_job.duration = -1.0;
291 receiver_ptr->enqueueFinalizerJob(std::move(shutdown_job));
296 for (
auto& finalizer_thread : _finalizer_threads)
298 if (finalizer_thread.joinable())
300 finalizer_thread.join();
304 LOG(Level::INFO,
"All finalization tasks complete.");
307 _reporter->report(
"Simulation complete", 100, 100);
309 LOG(Level::INFO,
"Event-driven simulation loop finished.");
313 const std::function<
void(
const std::string&,
int,
int)>& progress_callback,
314 const std::string& output_dir)
316 auto reporter = std::make_shared<ProgressReporter>(progress_callback);
317 auto metadata_collector = std::make_shared<OutputMetadataCollector>(output_dir);
320 return metadata_collector->snapshot();
Header for radar channel propagation and interaction models.
Encapsulates the state and logic of the event-driven simulation loop.
ComplexType calculateCwSample(radar::Receiver *rx, RealType t_step, const std::vector< radar::Transmitter * > &cw_sources) const
Calculates the total complex I/Q sample for a receiver at a specific time step.
void handleRxCwStart(radar::Receiver *rx)
Handles a continuous-wave receiver starting to record.
void handleRxPulsedWindowEnd(radar::Receiver *rx, RealType t_event)
Handles the closing of a pulsed receiver's listening window, triggering finalization.
void handleTxCwEnd(radar::Transmitter *tx)
Handles a continuous-wave transmitter turning off.
SimulationEngine(World *world, pool::ThreadPool &pool, std::shared_ptr< ProgressReporter > reporter, std::string output_dir, std::shared_ptr< OutputMetadataCollector > metadata_collector=nullptr)
Constructs the simulation engine.
void handleTxCwStart(radar::Transmitter *tx)
Handles a continuous-wave transmitter turning on.
void handleRxPulsedWindowStart(radar::Receiver *rx, RealType t_event)
Handles the opening of a pulsed receiver's listening window.
void run()
Starts and runs the main simulation loop until completion.
void processEvent(const Event &event)
Dispatches a discrete simulation event to its specific handler.
void processCwPhysics(RealType t_event)
Advances the time-stepped inner loop for active continuous-wave (CW) systems.
void handleRxCwEnd(radar::Receiver *rx)
Handles a continuous-wave receiver stopping recording.
void handleTxPulsedStart(radar::Transmitter *tx, RealType t_event)
Handles the start of a pulsed transmission.
The World class manages the simulator environment.
const std::vector< std::unique_ptr< radar::Target > > & getTargets() const noexcept
Retrieves the list of radar targets.
SimulationState & getSimulationState() noexcept
Gets a mutable reference to the global simulation state.
std::priority_queue< Event, std::vector< Event >, EventComparator > & getEventQueue() noexcept
Gets a mutable reference to the global event queue.
const std::vector< std::unique_ptr< radar::Receiver > > & getReceivers() const noexcept
Retrieves the list of radar receivers.
A simple thread pool implementation.
std::future< std::invoke_result_t< F, Args... > > enqueue(F &&f, Args &&... args)
Enqueues a task to be executed by the thread pool.
void wait()
Waits for all tasks in the thread pool to finish.
Manages radar signal reception and response processing.
void addInterferenceToLog(std::unique_ptr< serial::Response > response) noexcept
Adds a pulsed interference response to the receiver's CW-mode log.
void setActive(const bool active) noexcept
Sets the active state of the receiver.
bool checkFlag(RecvFlag flag) const noexcept
Checks if a specific flag is set.
std::vector< std::unique_ptr< serial::Response > > drainInbox() noexcept
Moves all responses from the inbox into a RenderingJob.
std::optional< RealType > getNextWindowTime(RealType time) const
Determines the next valid window start time at or after the given time.
void enqueueFinalizerJob(core::RenderingJob &&job)
Adds a completed RenderingJob to the finalizer queue.
OperationMode getMode() const noexcept
Gets the operational mode of the receiver.
RealType getWindowPrf() const noexcept
Retrieves the pulse repetition frequency (PRF) of the radar window.
void addResponseToInbox(std::unique_ptr< serial::Response > response) noexcept
Adds a response to the receiver's pulsed-mode inbox.
RealType getWindowLength() const noexcept
Retrieves the radar window length.
Represents a radar transmitter system.
RealType getPrf() const noexcept
Retrieves the pulse repetition frequency (PRF).
fers_signal::RadarSignal * getSignal() const noexcept
Retrieves the radar signal currently being transmitted.
std::optional< RealType > getNextPulseTime(RealType time) const
Determines the valid simulation time for a pulse at or after the given time.
double RealType
Type for real numbers.
std::complex< RealType > ComplexType
Type for complex numbers.
Declares the functions for the asynchronous receiver finalization pipelines.
Header file for the logging system.
OutputMetadata runEventDrivenSim(World *world, pool::ThreadPool &pool, const std::function< void(const std::string &, int, int)> &progress_callback, const std::string &output_dir)
Runs the unified, event-driven radar simulation.
@ RX_PULSED_WINDOW_START
A pulsed receiver opens its listening window.
@ RX_PULSED_WINDOW_END
A pulsed receiver closes its listening window.
@ TX_CW_START
A continuous-wave transmitter starts transmitting.
@ TX_CW_END
A continuous-wave transmitter stops transmitting.
@ TX_PULSED_START
A pulsed transmitter begins emitting a pulse.
@ RX_CW_END
A continuous-wave receiver stops listening.
@ RX_CW_START
A continuous-wave receiver starts listening.
RealType endTime() noexcept
Get the end time for the simulation.
RealType rate() noexcept
Get the rendering sample rate.
RealType startTime() noexcept
Get the start time for the simulation.
unsigned oversampleRatio() noexcept
Get the oversampling ratio.
void finalizeCwReceiver(radar::Receiver *receiver, pool::ThreadPool *, std::shared_ptr< core::ProgressReporter > reporter, const std::string &output_dir, std::shared_ptr< core::OutputMetadataCollector > metadata_collector)
The finalization task for a continuous-wave (CW) mode receiver.
void runPulsedFinalizer(radar::Receiver *receiver, const std::vector< std::unique_ptr< radar::Target > > *targets, std::shared_ptr< core::ProgressReporter > reporter, const std::string &output_dir, std::shared_ptr< core::OutputMetadataCollector > metadata_collector)
The main function for a dedicated pulsed-mode receiver finalizer thread.
OperationMode
Defines the operational mode of a radar component.
ComplexType calculateDirectPathContribution(const Transmitter *trans, const Receiver *recv, const RealType timeK)
Calculates the complex envelope contribution for a direct propagation path (Tx -> Rx) at a specific t...
std::unique_ptr< serial::Response > calculateResponse(const Transmitter *trans, const Receiver *recv, const RadarSignal *signal, const RealType startTime, const Target *targ)
Creates a Response object by simulating a signal's interaction over its duration.
ComplexType calculateReflectedPathContribution(const Transmitter *trans, const Receiver *recv, const Target *targ, const RealType timeK)
Calculates the complex envelope contribution for a reflected path (Tx -> Tgt -> Rx) at a specific tim...
Defines the Parameters struct and provides methods for managing simulation parameters.
Radar Receiver class for managing signal reception and response handling.
Defines the core structures for the event-driven simulation engine.
Header file for the main simulation runner.
Represents a single event in the simulation's time-ordered queue.
RealType timestamp
The simulation time at which the event occurs.
EventType type
The type of the event.
radar::Radar * source_object
Pointer to the object that generated the event.
A data packet containing all information needed to process one receive window.
RealType ideal_start_time
The ideal, jitter-free start time of the receive window.
std::vector< radar::Transmitter * > active_cw_transmitters
A global list of all currently active continuous-wave transmitters.
RealType t_current
The master simulation clock, advanced by the event loop.
Defines classes for radar targets and their Radar Cross-Section (RCS) models.
A simple thread pool implementation.
Header file for the Transmitter class in the radar namespace.
Header file for the World class in the simulator.