67 return static_cast<std::size_t
>(
73 return Vita49StreamMetadata{.receiver_id = stats.receiver_id,
74 .receiver_name = stats.receiver_name,
75 .stream_id = stats.stream_id,
77 .sample_rate = stats.sample_rate,
78 .reference_frequency = stats.reference_frequency,
79 .packets_emitted = stats.packets_emitted,
80 .samples_emitted = stats.samples_emitted,
81 .packets_dropped = stats.packets_dropped,
82 .samples_dropped = stats.samples_dropped,
83 .over_range_count = stats.over_range_count,
84 .late_packet_count = stats.late_packet_count,
85 .context_packet_count = stats.context_packets,
86 .first_sample_time = stats.first_sample_time,
87 .end_sample_time = stats.end_sample_time,
88 .first_timestamp = stats.first_timestamp,
89 .end_timestamp = stats.end_timestamp};
94 return count.has_value() ? std::format(
"{}", *count) : std::
string(
"unbounded");
105 "FMCW transmitter '{}' shape=linear {} B={} Hz T_c={} s T_rep={} s f_0={} Hz alpha={} Hz/s "
106 "duty_cycle={} chirp_count={} total_chirp_count={} average_power={} W",
125 "FMCW transmitter '{}' segment [{}, {}] shape=linear {} B={} Hz T_c={} s T_rep={} s f_0={} "
126 "Hz alpha={} Hz/s duty_cycle={} chirp_count={} segment_chirp_count={} total_chirp_count={} "
127 "average_power={} W",
158 "FMCW transmitter '{}' shape=triangle B={} Hz T_c={} s T_tri={} s f_0={} Hz alpha={} Hz/s "
159 "duty_cycle=1 triangle_count={} total_triangle_count={} average_power={} W",
178 "FMCW transmitter '{}' segment [{}, {}] shape=triangle B={} Hz T_c={} s T_tri={} s f_0={} "
179 "Hz alpha={} Hz/s duty_cycle=1 triangle_count={} segment_triangle_count={} "
180 "total_triangle_count={} average_power={} W",
210 "SFCW transmitter '{}' steps={} df={} Hz dwell={} s step_period={} s sweep_period={} s "
211 "f_first={} Hz f_last={} Hz B_eff={} Hz range_resolution={} m unambiguous_range={} m duty_cycle={} "
212 "sweep_count={} total_step_count={} average_power={} W",
234 "SFCW transmitter '{}' segment [{}, {}] steps={} df={} Hz dwell={} s step_period={} s "
235 "sweep_period={} s f_first={} Hz f_last={} Hz B_eff={} Hz range_resolution={} m "
236 "unambiguous_range={} m duty_cycle={} sweep_count={} segment_step_count={} total_step_count={} "
237 "average_power={} W",
279 [](
const auto&
period) { return period.end > params::endTime(); });
291 struct PositionBounds
366 const std::size_t
axis)
noexcept
377 if (
lhs.unbounded ||
rhs.unbounded || !
lhs.valid || !
rhs.valid)
379 return std::numeric_limits<RealType>::infinity();
404 const std::vector<math::Coord>&
coords,
501 for (std::size_t index = 0; index + 1 <
coords.size(); ++index)
512 std::clamp((std::max(start, segment_start) - segment_start) /
segment_length, 0.0, 1.0);
514 std::clamp((std::min(end, segment_end) - segment_start) /
segment_length, 0.0, 1.0);
523 struct QuadraticVelocityExtremum
535 const QuadraticVelocityExtremum&
extremum)
noexcept
557 const std::vector<math::Coord>&
coords,
581 QuadraticVelocityExtremum{.a =
a,
589 QuadraticVelocityExtremum{.a =
a,
600 QuadraticVelocityExtremum{.a =
a,
604 .root_u = -
b / (2.0 *
a),
627 for (std::size_t index = 0; index + 1 <
coords.size(); ++index)
649 return std::numeric_limits<RealType>::infinity();
653 for (std::size_t index = 0; index + 1 <
coords.size(); ++index)
663 std::clamp((std::max(start, segment_start) - segment_start) /
segment_length, 0.0, 1.0);
665 std::clamp((std::min(end, segment_end) - segment_start) /
segment_length, 0.0, 1.0);
720 const auto*
const tx = source.transmitter;
721 if (
tx ==
nullptr ||
rx ==
nullptr ||
tx->getPlatform() ==
rx->getPlatform() ||
params::c() <= 0.0)
726 const auto*
const tx_path =
tx->getPlatform()->getMotionPath();
727 const auto*
const rx_path =
rx->getPlatform()->getMotionPath();
746 const auto*
const tx = source.transmitter;
748 tx->getPlatform() ==
target->getPlatform() ||
rx->getPlatform() ==
target->getPlatform())
753 const auto*
const tx_path =
tx->getPlatform()->getMotionPath();
754 const auto*
const rx_path =
rx->getPlatform()->getMotionPath();
792 if (timestamp >= segment_start && timestamp < source.segment_end)
806 if (timestamp >=
active_start && timestamp < source.segment_end)
816 std::string output_dir,
817 std::shared_ptr<OutputMetadataCollector> metadata_collector,
820 _world(world), _pool(
pool), _reporter(std::
move(
reporter)), _metadata_collector(std::
move(metadata_collector)),
821 _output_sink(
output_sink), _cancel_callback(std::
move(cancel_callback)),
823 _next_context_heartbeat_time(
params::startTime() + 1.0), _output_dir(std::
move(output_dir)),
824 _internal_stop_time(
params::endTime())
826 _streaming_tracker_caches.resize(_world->
getReceivers().size());
827 _if_pulse_tracker_caches.resize(_world->
getReceivers().size());
828 _fmcw_if_block_buffers.resize(_world->
getReceivers().size());
830 _streaming_output_block_buffers.resize(_world->
getReceivers().size());
831 _streaming_output_processed_buffers.resize(_world->
getReceivers().size());
833 _streaming_output_block_start_indices.resize(_world->
getReceivers().size(), 0);
834 _streaming_downsamplers.resize(_world->
getReceivers().size());
835 _streaming_downsample_base_indices.resize(_world->
getReceivers().size(), 0);
837 _streaming_output_sample_cursors.resize(_world->
getReceivers().size(), 0);
838 _streaming_output_stream_ids.resize(_world->
getReceivers().size(), 0);
839 _streaming_output_stream_open.resize(_world->
getReceivers().size(),
false);
840 _streaming_output_file_metadata.resize(_world->
getReceivers().size());
841 for (
auto&
block : _streaming_output_block_buffers)
845 for (
auto&
block : _streaming_output_processed_buffers)
855 _reporter->report(
"Initializing event-driven simulation...", 0, 100);
858 initializeFmcwIfResamplers();
862 initializeFinalizers();
864 LOG(Level::INFO,
"Starting unified event-driven simulation loop.");
865 logStreamingSummaries();
869 const RealType end_time = _internal_stop_time;
873 if (isCancellationRequested())
881 if (isCancellationRequested())
886 flushStreamingOutputBlocks();
888 state.t_current =
event.timestamp;
896 { return receiver->isActive() && receiver->hasFmcwIfResamplingSink(); });
902 flushStreamingOutputBlocks();
907 void SimulationEngine::logStreamingSummaries()
const
912 if (waveform ==
nullptr)
932 void SimulationEngine::initializeFinalizers()
934 if (_output_sink ==
nullptr)
940 if (
receiver_ptr->getMode() == OperationMode::PULSED_MODE)
943 &_world->
getTargets(), _reporter, _output_dir, _metadata_collector,
949 void SimulationEngine::initializeFmcwIfResamplers()
959 extendDechirpSourcesForIfOverrender();
963 void SimulationEngine::initializeFmcwIfResampler(
const std::size_t
receiver_index)
977 .filter_bandwidth_hz = bandwidth,
978 .filter_transition_width_hz =
request.filter_transition_width_hz};
983 if (_output_sink !=
nullptr)
986 [
this,
receiver_index](
const std::span<const ComplexType> samples,
const std::uint64_t sample_start)
995 static_cast<RealType>(sample_start) /
if_plan->actual_output_sample_rate_hz;
997 samples, sample_start);
1000 const RealType actual_output_sample_rate_hz = plan.actual_output_sample_rate_hz;
1001 const auto overall_ratio = plan.overall_ratio;
1002 const RealType filter_bandwidth_hz = plan.filter_bandwidth_hz;
1003 const RealType filter_transition_width_hz = plan.filter_transition_width_hz;
1004 receiver_ptr->initializeFmcwIfResampling(std::move(plan));
1006 "Receiver '{}' enabled FMCW IF resampling: input_rate={} Hz requested_output_rate={} Hz "
1007 "actual_output_rate={} Hz ratio={}/{} passband={} Hz transition={} Hz.",
1009 overall_ratio.numerator, overall_ratio.denominator, filter_bandwidth_hz, filter_transition_width_hz);
1012 void SimulationEngine::extendDechirpSourcesForIfOverrender()
1014 for (
const auto&
receiver_ptr : _world->getReceivers())
1028 if (source.transmitter ==
nullptr || source.transmitter->getSchedule().empty())
1030 source.segment_end = _internal_stop_time;
1037 source.segment_end = std::min(_internal_stop_time,
period.end);
1046 void SimulationEngine::ensureCwPhaseNoiseLookup()
1048 if (_cw_phase_noise_lookup)
1055 for (
const auto& source : _world->getSimulationState().active_streaming_transmitters)
1059 _cw_phase_noise_lookup = std::make_unique<simulation::CwPhaseNoiseLookup>(
1066 auto& t_current =
state.t_current;
1079 ensureCwPhaseNoiseLookup();
1081 while (t_current <
t_event && !isCancellationRequested())
1083 cleanupInactiveStreamingSources(t_current);
1103 emitContextHeartbeatsThrough(t_current);
1105 cleanupInactiveStreamingSources(t_current);
1108 std::optional<RealType> SimulationEngine::nextStreamingCleanupDeadline(
const RealType from_time)
1112 for (
const auto& source : active_streaming_transmitters)
1150 if (_output_sink !=
nullptr &&
t_step >= _next_context_heartbeat_time)
1152 emitContextHeartbeatsThrough(
t_step);
1156 reportSimulationProgress(
t_step);
1168 void SimulationEngine::appendReceiverStreamingSample(
const std::size_t
receiver_index,
1184 else if (_output_sink !=
nullptr)
1198 block.push_back(sample);
1208 if (_eager_context_stream_open)
1218 block.push_back(sample);
1225 void SimulationEngine::flushStreamingOutputBlocks()
1289 else if (!dechirped)
1317 _streaming_downsamplers[
receiver_index] = std::make_unique<fers_signal::DownsamplingSink>();
1336 return if_plan.has_value() ?
if_plan->actual_output_sample_rate_hz : 0.0;
1345 void SimulationEngine::ensureStreamingOutputStreamOpen(
const std::size_t
receiver_index,
1378 void SimulationEngine::emitStreamingOutputBlock(
const std::size_t
receiver_index,
const RealType first_sample_time,
1380 const std::span<const ComplexType> samples,
1381 const std::uint64_t sample_start)
1390 processed.assign(samples.begin(), samples.end());
1395 ensureStreamingOutputStreamOpen(
receiver_index, first_sample_time, sample_rate);
1401 _streaming_output_sample_cursors[
receiver_index] = sample_start +
static_cast<std::uint64_t
>(
processed.size());
1406 if (_output_sink ==
nullptr)
1418 _next_context_heartbeat_time += 1.0;
1426 void SimulationEngine::flushFmcwIfBlocks()
1434 void SimulationEngine::flushFmcwIfBlock(
const std::size_t
receiver_index)
1457 void SimulationEngine::applyPulsedInterferenceToFmcwIfBlock(
const std::size_t
receiver_index,
1458 std::span<ComplexType>
block,
1466 void SimulationEngine::addPulsedInterferenceSamples(std::span<ComplexType>
block,
1484 if (!
mixer.has_value())
1497 void SimulationEngine::applyPulsedInterferenceToStreamingBlock(
const std::size_t
receiver_index,
1498 std::span<ComplexType>
block,
1508 if (!std::isfinite(sample_rate) || sample_rate <= 0.0)
1534 const auto dest_begin =
static_cast<long long>(
1536 const auto dest_end =
static_cast<long long>(std::min<RealType>(
1568 std::ranges::fill(
tracker_cache.dechirp_reference, FmcwChirpBoundaryTracker{});
1591 return std::nullopt;
1595 if (
rx->getDechirpMode() == Receiver::DechirpMode::Physical && _cw_phase_noise_lookup)
1618 : (
rx->getDechirpMode() == Receiver::DechirpMode::Ideal
1626 if (!
rx->checkFlag(Receiver::RecvFlag::FLAG_NODIRECT))
1656 void SimulationEngine::appendStreamingTrackerSource()
1660 for (
auto&
cache : _streaming_tracker_caches)
1662 cache.direct.emplace_back();
1667 void SimulationEngine::eraseStreamingTrackerSource(
const std::size_t
source_index)
1669 for (
auto&
cache : _streaming_tracker_caches)
1682 void SimulationEngine::cleanupInactiveStreamingSources(
const RealType from_time)
1698 sources.erase(
sources.begin() +
static_cast<std::ptrdiff_t
>(index));
1699 eraseStreamingTrackerSource(index);
1703 std::optional<RealType> SimulationEngine::streamingSourceCleanupDeadline(
const ActiveStreamingSource& source,
1706 if (source.transmitter ==
nullptr || source.carrier_freq <= 0.0)
1708 return std::nullopt;
1712 for (
const auto&
receiver_ptr : _world->getReceivers())
1724 std::optional<RealType> SimulationEngine::receiverCleanupDeadline(
const ActiveStreamingSource& source,
1730 return std::nullopt;
1748 return std::nullopt;
1751 std::optional<RealType>
latest;
1752 if (!
rx->checkFlag(Receiver::RecvFlag::FLAG_NODIRECT))
1756 for (
const auto&
target_ptr : _world->getTargets())
1813 void SimulationEngine::routeResponse(
Receiver*
rx, std::unique_ptr<serial::Response>
response)
const
1819 if (
rx->getMode() == OperationMode::PULSED_MODE)
1825 rx->addInterferenceToLog(std::move(
response));
1833 if (!
rx_ptr->checkFlag(Receiver::RecvFlag::FLAG_NODIRECT))
1855 rx->setActive(
true);
1861 rx->setActive(
false);
1862 const auto active_streaming_sources =
1863 collectStreamingSourcesForWindow(
t_event -
rx->getWindowLength(),
t_event);
1866 .duration =
rx->getWindowLength(),
1867 .responses =
rx->drainInbox(),
1868 .active_streaming_sources = active_streaming_sources};
1870 rx->enqueueFinalizerJob(std::move(
job));
1883 appendStreamingTrackerSource();
1896 rx->setActive(
true);
1898 { return receiver_ptr.get() == rx; });
1903 if (_eager_context_stream_open)
1909 if (
rx->hasFmcwIfResamplingSink())
1918 { return receiver_ptr.get() == rx; });
1930 if (
rx->hasFmcwIfResamplingSink())
1932 rx->endFmcwIfResamplingSegment();
1943 rx->setActive(
false);
1948 bool SimulationEngine::isCancellationRequested()
1954 if (_cancel_callback && _cancel_callback())
1957 LOG(Level::INFO,
"Simulation cancellation requested.");
1960 _reporter->report(
"Simulation cancelled", 100, 100);
1967 void SimulationEngine::reportSimulationProgress(
const RealType t_current)
1976 const RealType duration = end_time - start_time;
1978 const int progress =
static_cast<int>(
1981 if (
const auto now = std::chrono::steady_clock::now();
1982 progress != _last_reported_percent ||
now - _last_report_time >= std::chrono::milliseconds(100))
1984 _reporter->report(std::format(
"Simulating... {:.2f}s / {:.2f}s", t_current, end_time),
progress, 100);
1986 _last_report_time =
now;
1990 std::vector<ActiveStreamingSource> SimulationEngine::collectStreamingSourcesForWindow(
const RealType start_time,
1995 std::vector<ActiveStreamingSource>
sources;
2006 if (source.segment_start < source.segment_end && source.segment_start < end_time)
2026 void SimulationEngine::shutdown()
2028 LOG(Level::INFO,
"Simulation compute loop finished. Waiting for receiver finalization tasks...");
2031 _reporter->report(
"Simulation compute finished. Waiting for receiver finalization...", 100, 100);
2039 if (_output_sink !=
nullptr)
2051 else if (
receiver_ptr->getMode() == OperationMode::PULSED_MODE)
2068 LOG(Level::INFO,
"All finalization tasks complete.");
2072 const std::function<
void(
const std::string&,
int,
int)>& progress_callback,
2074 std::function<
bool()> cancel_callback,
bool* cancelled,
2077 if (cancelled !=
nullptr)
2081 auto reporter = std::make_shared<ProgressReporter>(progress_callback);
2082 auto metadata_collector = std::make_shared<OutputMetadataCollector>(output_dir);
2098 if (cancelled !=
nullptr)
2100 *cancelled =
engine.cancelled();
2104 LOG(Level::INFO,
"Waiting for VITA output stream drain...");
2105 reporter->report(
"Waiting for VITA output stream drain...", 100, 100);
2108 reporter->report(
engine.cancelled() ?
"Simulation cancelled" :
"Simulation complete", 100, 100);
2109 LOG(Level::INFO,
"Event-driven simulation loop finished.");
2110 auto metadata = metadata_collector->snapshot();
2116 if (stats.epoch_unix_nanoseconds.has_value())
2118 vita49_metadata.epoch_unix_nanoseconds = stats.epoch_unix_nanoseconds;
2120 for (
const auto& stream : stats.streams)
const Transmitter & transmitter
const Receiver & receiver
Header for radar channel propagation and interaction models.
virtual void emitContextHeartbeat(RealType simulation_time)=0
virtual void submitBlock(const ReceiverSampleBlock &block)=0
virtual std::uint32_t registerStream(const ReceiverStreamDescriptor &stream)=0
virtual void closeStream(std::uint32_t stream_id)=0
virtual void openStream(std::uint32_t stream_id, RealType first_sample_time)=0
Encapsulates the state and logic of the event-driven simulation loop.
void handleRxStreamingStart(radar::Receiver *rx)
Handles a streaming receiver starting to record.
void handleTxStreamingEnd(radar::Transmitter *tx)
Handles a streaming transmitter turning off.
void handleRxPulsedWindowEnd(radar::Receiver *rx, RealType t_event)
Handles the closing of a pulsed receiver's listening window, triggering finalization.
SimulationEngine(World *world, pool::ThreadPool &pool, std::shared_ptr< ProgressReporter > reporter, std::string output_dir, std::shared_ptr< OutputMetadataCollector > metadata_collector=nullptr, ReceiverOutputSink *output_sink=nullptr, std::function< bool()> cancel_callback=nullptr, bool eager_context_stream_open=false)
Constructs the simulation engine.
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 handleTxStreamingStart(const ActiveStreamingSource &source)
Handles a streaming transmitter turning on.
void handleRxStreamingEnd(radar::Receiver *rx)
Handles a streaming receiver stopping recording.
void processStreamingPhysics(RealType t_event)
Advances the time-stepped inner loop for active streaming systems.
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.
RealType earliestPhaseNoiseLookupStart() const
Finds the earliest simulation time that can require CW phase-noise samples.
Stateful FIR decimator for chunked streaming output.
FMCW linear chirp signal implementation.
RealType getChirpDuration() const noexcept
Gets the chirp duration in seconds.
RealType getChirpBandwidth() const noexcept
Gets the chirp bandwidth in hertz.
RealType getChirpPeriod() const noexcept
Gets the chirp period in seconds.
FmcwChirpDirection getDirection() const noexcept
Gets the FMCW sweep direction.
const std::optional< std::size_t > & getChirpCount() const noexcept
Gets the optional finite chirp count.
RealType getChirpRate() const noexcept
Gets the chirp rate in hertz per second.
RealType getStartFrequencyOffset() const noexcept
Gets the start frequency offset relative to carrier in hertz.
FMCW symmetric triangular modulation signal implementation.
RealType getStartFrequencyOffset() const noexcept
Gets the start frequency offset relative to carrier in hertz.
RealType getChirpBandwidth() const noexcept
Gets the chirp bandwidth in hertz.
RealType getChirpRate() const noexcept
Gets the chirp rate magnitude in hertz per second.
const std::optional< std::size_t > & getTriangleCount() const noexcept
Gets the optional finite triangle count.
RealType getChirpDuration() const noexcept
Gets the per-leg chirp duration in seconds.
RealType getTrianglePeriod() const noexcept
Gets the full up/down triangle period in seconds.
Class representing a radar signal with associated properties.
const class SteppedFrequencySignal * getSteppedFrequencySignal() const noexcept
Gets the stepped-frequency implementation, if this signal owns one.
const class FmcwTriangleSignal * getFmcwTriangleSignal() const noexcept
Gets the FMCW triangle implementation, if this signal owns one.
RealType getCarrier() const noexcept
Gets the carrier frequency of the radar signal.
const class FmcwChirpSignal * getFmcwChirpSignal() const noexcept
Gets the FMCW chirp implementation, if this signal owns one.
RealType getPower() const noexcept
Gets the power of the radar signal.
Stepped-frequency continuous-wave signal implementation.
RealType effectiveBandwidth() const noexcept
Gets DFT-convention effective bandwidth in hertz.
RealType getSweepPeriod() const noexcept
Gets full sweep period in seconds.
const std::optional< std::size_t > & getSweepCount() const noexcept
Gets optional finite sweep count.
RealType getStepSize() const noexcept
Gets the uniform frequency step in hertz.
RealType lastFrequency(RealType carrier_frequency) const noexcept
Gets final-step RF frequency in hertz.
RealType firstFrequency(RealType carrier_frequency) const noexcept
Gets first-step RF frequency in hertz.
std::size_t getStepCount() const noexcept
Gets the number of steps per sweep.
RealType getStepPeriod() const noexcept
Gets step repetition period in seconds.
RealType getDwellTime() const noexcept
Gets active dwell time per step in seconds.
Exception class for handling path-related errors.
Represents a path with coordinates and allows for various interpolation methods.
Vec3 getPosition(RealType t) const
Retrieves the position at a given time along the path.
const std::vector< Coord > & getCoords() const noexcept
Gets the list of coordinates in the path.
@ INTERP_STATIC
Hold the first coordinate for all query times.
@ INTERP_LINEAR
Linearly interpolate between neighboring coordinates.
@ INTERP_CUBIC
Cubically interpolate between neighboring coordinates.
InterpType getType() const noexcept
Retrieves the current interpolation type of the path.
A class representing a vector in rectangular coordinates.
RealType x
The x component of the vector.
RealType z
The z component of the vector.
RealType y
The y component of the vector.
A simple thread pool implementation.
void wait()
Waits for all tasks in the thread pool to finish.
const std::string & getName() const noexcept
Retrieves the name of the object.
Manages radar signal reception and response processing.
std::mt19937 & getRngEngine() noexcept
Gets the receiver's internal random number generator engine.
bool hasFmcwIfResamplingSink() const noexcept
Returns true when this receiver is using the online FMCW IF resampling sink.
void prunePulsedInterferenceEndingBefore(RealType cutoff_time) noexcept
Removes logged pulsed interference responses that ended before a receive time.
const std::vector< SchedulePeriod > & getSchedule() const noexcept
Retrieves the list of active reception periods.
bool isDechirpEnabled() const noexcept
Returns true when the receiver emits dechirped IF data.
void consumeFmcwIfBlock(std::span< const ComplexType > block, RealType block_start_time)
Feeds one completed high-rate dechirped block into the online IF sink.
const std::optional< fers_signal::FmcwIfResamplerPlan > & getFmcwIfResamplerPlan() const noexcept
Gets the active or most recently used IF resampling plan, if any.
RealType getNoiseTemperature() const noexcept
Retrieves the noise temperature of the receiver.
OperationMode getMode() const noexcept
Gets the operational mode of the receiver.
Base class for radar targets.
Represents a radar transmitter system.
bool isStreamingMode() const noexcept
Returns true when the transmitter uses a continuous streaming mode.
const std::vector< SchedulePeriod > & getSchedule() const noexcept
Retrieves the list of active transmission periods.
double RealType
Type for real numbers.
constexpr RealType EPSILON
Machine epsilon for real numbers.
std::complex< RealType > ComplexType
Type for complex numbers.
Declares the functions for the asynchronous receiver finalization pipelines.
Declares focused, testable pipeline steps for receiver finalization.
Internal FMCW IF rational resampler planning and streaming sink.
Header file for the logging system.
Startup memory and output-size projection helpers for simulations.
std::uint64_t countFmcwTriangleStarts(const ActiveStreamingSource &source, const RealType active_start, const RealType active_end)
Counts FMCW triangles that start inside the absolute interval.
std::uint64_t countSfcwStepStarts(const ActiveStreamingSource &source, const RealType active_start, const RealType active_end)
Counts SFCW active dwells that start inside the absolute interval.
void logSimulationMemoryProjection(const World &world)
Logs the projected simulation memory footprint for the provided world.
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.
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, std::function< bool()> cancel_callback, bool *cancelled, ReceiverOutputTelemetryCallback telemetry_callback)
Runs the unified, event-driven radar simulation.
std::function< void(const std::optional< OutputStats > &, std::span< const ReceiverOutputPacketTrace >)> ReceiverOutputTelemetryCallback
bool isVita49Enabled(const OutputConfig &config) noexcept
@ 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.
Vita49OutputMetadata vita49MetadataFromConfig(const Vita49OutputConfig &config)
Builds the static VITA metadata section from runtime output configuration.
std::vector< std::shared_ptr< timing::Timing > > collectCwPhaseNoiseTimings(const World &world)
Collects unique timing sources used by CW/FMCW transmitters and receivers.
std::uint64_t countFmcwChirpStarts(const ActiveStreamingSource &source, const RealType active_start, const RealType active_end)
Counts FMCW chirps that start inside the absolute interval.
FmcwIfResamplerPlan planFmcwIfResampler(const FmcwIfResamplerRequest &request)
std::string_view fmcwChirpDirectionToken(const FmcwChirpDirection direction) noexcept
Converts a chirp direction to the schema token.
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.
unsigned renderFilterLength() noexcept
Get the render filter length.
Parameters params
Global simulation parameter state.
RealType c() noexcept
Get the speed of light.
core::ReceiverSampleBlock buildReceiverSampleBlock(const radar::Receiver *receiver, const RealType first_sample_time, const RealType sample_rate, const std::span< const ComplexType > samples, const std::uint64_t sample_start, std::shared_ptr< const core::OutputFileMetadata > file_metadata)
Builds a non-owning output sample block over contiguous processed complex samples.
void runPulsedFinalizer(radar::Receiver *receiver, const std::vector< std::unique_ptr< radar::Target > > *targets, const std::shared_ptr< core::ProgressReporter > &reporter, const std::string &output_dir, const std::shared_ptr< core::OutputMetadataCollector > &metadata_collector, core::ReceiverOutputSink *output_sink)
The main function for a dedicated pulsed-mode receiver finalizer thread.
core::OutputFileMetadata buildStreamingOutputMetadata(const radar::Receiver *receiver, const std::string &output_path, const std::size_t total_samples, const std::vector< core::ActiveStreamingSource > &streaming_sources, const RealType output_sample_rate)
Builds HDF5 file metadata for a streaming receiver result emitted through the output sink.
void applyThermalNoiseAtSampleRate(std::span< ComplexType > window, const RealType noiseTemperature, std::mt19937 &rngEngine, const RealType sampleRateHz)
Applies circular complex thermal noise using a caller-specified complex-baseband sample rate.
core::ReceiverStreamDescriptor buildReceiverStreamDescriptor(const radar::Receiver *receiver, const RealType sample_rate, const std::span< const core::ActiveStreamingSource > streaming_sources)
Builds the receiver stream descriptor used by output sinks.
OperationMode
Defines the operational mode of a radar component.
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)
ComplexType calculateStreamingDirectPathContribution(const core::ActiveStreamingSource &source, const Receiver *recv, const RealType timeK, const CwPhaseNoiseLookup *const phase_noise_lookup, core::FmcwChirpBoundaryTracker *const chirp_tracker, const StreamingTimingPhaseMode timing_phase_mode)
Calculates a direct-path contribution from a cached streaming source.
bool calculateStreamingReferencePhase(const core::ActiveStreamingSource &source, const RealType timeK, core::FmcwChirpBoundaryTracker *const chirp_tracker, RealType &phase_out)
Evaluates a receive-time streaming waveform phase for receiver LO/dechirp references.
@ TransmitterOnly
Incoming RF/baseband signal before receiver LO subtraction.
@ None
Ignore timing phase noise entirely.
@ ReceiverRelative
Existing raw streaming convention: transmitter phase minus receiver LO phase.
ComplexType calculateStreamingReflectedPathContribution(const core::ActiveStreamingSource &source, const Receiver *recv, const Target *targ, const RealType timeK, const CwPhaseNoiseLookup *const phase_noise_lookup, core::FmcwChirpBoundaryTracker *const chirp_tracker, const StreamingTimingPhaseMode timing_phase_mode)
Calculates a reflected-path contribution from a cached streaming source.
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.
Defines the Parameters struct and provides methods for managing simulation parameters.
Utility functions for path interpolation and exception handling.
Classes for handling radar waveforms and signals.
Radar Receiver class for managing signal reception and response handling.
Classes for managing radar signal responses.
Header for receiver-side signal processing and rendering.
Defines the core structures for the event-driven simulation engine.
Header file for the main simulation runner.
Cached description of an active streaming transmitter segment.
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.
std::vector< ActiveStreamingSource > active_streaming_transmitters
A global list of all currently active streaming transmitters.
RealType t_current
The master simulation clock, advanced by the event loop.
Represents a position in 3D space with an associated time.
static CwPhaseNoiseLookup build(std::span< const std::shared_ptr< timing::Timing > > timings, RealType start_time, RealType end_time)
Builds a phase-noise lookup for the requested timing sources and time range.
Defines classes for radar targets and their Radar Cross-Section (RCS) models.
A simple thread pool implementation.
Timing source for simulation objects.
Header file for the Transmitter class in the radar namespace.
Header file for the World class in the simulator.