58 const std::function<
void(
const std::string&,
int,
int)>& progress_callback)
66 auto reporter = std::make_shared<ProgressReporter>(progress_callback);
68 if (progress_callback)
70 reporter->report(
"Initializing event-driven simulation...", 0, 100);
75 std::vector<std::jthread> finalizer_threads;
78 if (receiver_ptr->getMode() == OperationMode::PULSED_MODE)
85 LOG(Level::INFO,
"Starting unified event-driven simulation loop.");
88 auto last_report_time = std::chrono::steady_clock::now();
89 int last_reported_percent = -1;
90 const auto report_interval = std::chrono::milliseconds(100);
93 while (!event_queue.empty() && t_current <= end_time)
96 const auto [timestamp, event_type, source_object] = event_queue.top();
104 if (t_event > t_current)
106 const RealType t_next_event = t_event;
108 const auto start_index =
static_cast<size_t>(std::ceil((t_current -
params::startTime()) / dt_sim));
109 const auto end_index =
static_cast<size_t>(std::ceil((t_next_event -
params::startTime()) / dt_sim));
111 for (
size_t sample_index = start_index; sample_index < end_index; ++sample_index)
117 if (receiver_ptr->getMode() == OperationMode::CW_MODE && receiver_ptr->isActive())
121 for (
const auto& cw_source : active_cw_transmitters)
124 if (!receiver_ptr->checkFlag(Receiver::RecvFlag::FLAG_NODIRECT))
127 cw_source, receiver_ptr.get(), t_step);
129 for (
const auto& target_ptr : world->
getTargets())
132 cw_source, receiver_ptr.get(), target_ptr.get(), t_step);
136 receiver_ptr->setCwSample(sample_index, total_sample);
150 auto* tx =
static_cast<Transmitter*
>(source_object);
155 if (!rx_ptr->checkFlag(Receiver::RecvFlag::FLAG_NODIRECT))
160 if (rx_ptr->getMode() == OperationMode::PULSED_MODE)
162 rx_ptr->addResponseToInbox(std::move(response));
166 rx_ptr->addInterferenceToLog(std::move(response));
170 for (
const auto& target_ptr : world->
getTargets())
173 t_event, target_ptr.get()))
175 if (rx_ptr->getMode() == OperationMode::PULSED_MODE)
177 rx_ptr->addResponseToInbox(std::move(response));
181 rx_ptr->addInterferenceToLog(std::move(response));
187 const RealType next_theoretical_time = t_event + 1.0 / tx->
getPrf();
190 if (
const auto next_pulse_opt = tx->getNextPulseTime(next_theoretical_time);
191 next_pulse_opt && *next_pulse_opt <= end_time)
200 auto* rx =
static_cast<Receiver*
>(source_object);
208 auto* rx =
static_cast<Receiver*
>(source_object);
212 .duration = rx->getWindowLength(),
213 .responses = rx->drainInbox(),
214 .active_cw_sources = active_cw_transmitters};
216 rx->enqueueFinalizerJob(std::move(job));
219 const RealType next_theoretical = t_event - rx->getWindowLength() + 1.0 / rx->getWindowPrf();
221 if (
const auto next_start = rx->getNextWindowTime(next_theoretical);
222 next_start && *next_start <= end_time)
231 auto* tx =
static_cast<Transmitter*
>(source_object);
232 active_cw_transmitters.push_back(tx);
238 auto* tx =
static_cast<Transmitter*
>(source_object);
239 std::erase(active_cw_transmitters, tx);
245 auto* rx =
static_cast<Receiver*
>(source_object);
252 auto* rx =
static_cast<Receiver*
>(source_object);
261 if (progress_callback)
263 const int progress =
static_cast<int>(t_current / end_time * 100.0);
266 if (
const auto now = std::chrono::steady_clock::now();
267 progress != last_reported_percent || now - last_report_time >= report_interval)
269 reporter->report(std::format(
"Simulating... {:.2f}s / {:.2f}s", t_current, end_time), progress,
271 last_reported_percent = progress;
272 last_report_time = now;
278 LOG(Level::INFO,
"Main simulation loop finished. Waiting for finalization tasks...");
279 reporter->report(
"Main simulation finished. Waiting for data export...", 100, 100);
285 if (receiver_ptr->getMode() == OperationMode::CW_MODE)
294 if (receiver_ptr->getMode() == OperationMode::PULSED_MODE)
297 receiver_ptr->enqueueFinalizerJob(std::move(shutdown_job));
305 LOG(Level::INFO,
"All finalization tasks complete.");
307 if (progress_callback)
309 reporter->report(
"Simulation complete", 100, 100);
311 LOG(Level::INFO,
"Event-driven simulation loop finished.");
Header for radar channel propagation and interaction models.
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.
Manages radar signal reception and response processing.
void setActive(const bool active) noexcept
Sets the active state of the receiver.
Base class for radar targets.
Represents a radar transmitter system.
RealType getPrf() const noexcept
Retrieves the pulse repetition frequency (PRF).
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.
@ 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.
void runEventDrivenSim(World *world, pool::ThreadPool &pool, const std::function< void(const std::string &, int, int)> &progress_callback)
Runs the unified, event-driven radar simulation.
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 runPulsedFinalizer(radar::Receiver *receiver, const std::vector< std::unique_ptr< radar::Target > > *targets, std::shared_ptr< core::ProgressReporter > reporter)
The main function for a dedicated pulsed-mode receiver finalizer thread.
void finalizeCwReceiver(radar::Receiver *receiver, pool::ThreadPool *pool, std::shared_ptr< core::ProgressReporter > reporter)
The finalization task for a continuous-wave (CW) mode receiver.
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.
A data packet containing all information needed to process one receive window.
RealType duration
The duration of the receive window in seconds.
RealType ideal_start_time
The ideal, jitter-free start time of the receive window.
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.