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",
218 [](
const auto&
period) { return period.end > params::endTime(); });
230 struct PositionBounds
305 const std::size_t
axis)
noexcept
316 if (
lhs.unbounded ||
rhs.unbounded || !
lhs.valid || !
rhs.valid)
318 return std::numeric_limits<RealType>::infinity();
343 const std::vector<math::Coord>&
coords,
440 for (std::size_t index = 0; index + 1 <
coords.size(); ++index)
451 std::clamp((std::max(start, segment_start) - segment_start) /
segment_length, 0.0, 1.0);
453 std::clamp((std::min(end, segment_end) - segment_start) /
segment_length, 0.0, 1.0);
462 struct QuadraticVelocityExtremum
474 const QuadraticVelocityExtremum&
extremum)
noexcept
496 const std::vector<math::Coord>&
coords,
520 QuadraticVelocityExtremum{.a =
a,
528 QuadraticVelocityExtremum{.a =
a,
539 QuadraticVelocityExtremum{.a =
a,
543 .root_u = -
b / (2.0 *
a),
566 for (std::size_t index = 0; index + 1 <
coords.size(); ++index)
588 return std::numeric_limits<RealType>::infinity();
592 for (std::size_t index = 0; index + 1 <
coords.size(); ++index)
602 std::clamp((std::max(start, segment_start) - segment_start) /
segment_length, 0.0, 1.0);
604 std::clamp((std::min(end, segment_end) - segment_start) /
segment_length, 0.0, 1.0);
659 const auto*
const tx = source.transmitter;
660 if (
tx ==
nullptr ||
rx ==
nullptr ||
tx->getPlatform() ==
rx->getPlatform() ||
params::c() <= 0.0)
665 const auto*
const tx_path =
tx->getPlatform()->getMotionPath();
666 const auto*
const rx_path =
rx->getPlatform()->getMotionPath();
685 const auto*
const tx = source.transmitter;
687 tx->getPlatform() ==
target->getPlatform() ||
rx->getPlatform() ==
target->getPlatform())
692 const auto*
const tx_path =
tx->getPlatform()->getMotionPath();
693 const auto*
const rx_path =
rx->getPlatform()->getMotionPath();
731 if (timestamp >= segment_start && timestamp < source.segment_end)
745 if (timestamp >=
active_start && timestamp < source.segment_end)
755 std::string output_dir,
756 std::shared_ptr<OutputMetadataCollector> metadata_collector,
759 _world(world), _pool(
pool), _reporter(std::
move(
reporter)), _metadata_collector(std::
move(metadata_collector)),
760 _output_sink(
output_sink), _cancel_callback(std::
move(cancel_callback)),
762 _next_context_heartbeat_time(
params::startTime() + 1.0), _output_dir(std::
move(output_dir)),
763 _internal_stop_time(
params::endTime())
765 _streaming_tracker_caches.resize(_world->
getReceivers().size());
766 _if_pulse_tracker_caches.resize(_world->
getReceivers().size());
767 _fmcw_if_block_buffers.resize(_world->
getReceivers().size());
769 _streaming_output_block_buffers.resize(_world->
getReceivers().size());
770 _streaming_output_processed_buffers.resize(_world->
getReceivers().size());
772 _streaming_output_block_start_indices.resize(_world->
getReceivers().size(), 0);
773 _streaming_downsamplers.resize(_world->
getReceivers().size());
774 _streaming_downsample_base_indices.resize(_world->
getReceivers().size(), 0);
776 _streaming_output_sample_cursors.resize(_world->
getReceivers().size(), 0);
777 _streaming_output_stream_ids.resize(_world->
getReceivers().size(), 0);
778 _streaming_output_stream_open.resize(_world->
getReceivers().size(),
false);
779 _streaming_output_file_metadata.resize(_world->
getReceivers().size());
780 for (
auto&
block : _streaming_output_block_buffers)
784 for (
auto&
block : _streaming_output_processed_buffers)
794 _reporter->report(
"Initializing event-driven simulation...", 0, 100);
797 initializeFmcwIfResamplers();
801 initializeFinalizers();
803 LOG(Level::INFO,
"Starting unified event-driven simulation loop.");
804 logStreamingSummaries();
808 const RealType end_time = _internal_stop_time;
812 if (isCancellationRequested())
820 if (isCancellationRequested())
825 flushStreamingOutputBlocks();
827 state.t_current =
event.timestamp;
835 { return receiver->isActive() && receiver->hasFmcwIfResamplingSink(); });
841 flushStreamingOutputBlocks();
846 void SimulationEngine::logStreamingSummaries()
const
867 void SimulationEngine::initializeFinalizers()
869 if (_output_sink ==
nullptr)
875 if (
receiver_ptr->getMode() == OperationMode::PULSED_MODE)
878 &_world->
getTargets(), _reporter, _output_dir, _metadata_collector,
884 void SimulationEngine::initializeFmcwIfResamplers()
894 extendDechirpSourcesForIfOverrender();
898 void SimulationEngine::initializeFmcwIfResampler(
const std::size_t
receiver_index)
912 .filter_bandwidth_hz = bandwidth,
913 .filter_transition_width_hz =
request.filter_transition_width_hz};
918 if (_output_sink !=
nullptr)
921 [
this,
receiver_index](
const std::span<const ComplexType> samples,
const std::uint64_t sample_start)
930 static_cast<RealType>(sample_start) /
if_plan->actual_output_sample_rate_hz;
932 samples, sample_start);
935 const RealType actual_output_sample_rate_hz = plan.actual_output_sample_rate_hz;
936 const auto overall_ratio = plan.overall_ratio;
937 const RealType filter_bandwidth_hz = plan.filter_bandwidth_hz;
938 const RealType filter_transition_width_hz = plan.filter_transition_width_hz;
939 receiver_ptr->initializeFmcwIfResampling(std::move(plan));
941 "Receiver '{}' enabled FMCW IF resampling: input_rate={} Hz requested_output_rate={} Hz "
942 "actual_output_rate={} Hz ratio={}/{} passband={} Hz transition={} Hz.",
944 overall_ratio.numerator, overall_ratio.denominator, filter_bandwidth_hz, filter_transition_width_hz);
947 void SimulationEngine::extendDechirpSourcesForIfOverrender()
963 if (source.transmitter ==
nullptr || source.transmitter->getSchedule().empty())
965 source.segment_end = _internal_stop_time;
972 source.segment_end = std::min(_internal_stop_time,
period.end);
981 void SimulationEngine::ensureCwPhaseNoiseLookup()
983 if (_cw_phase_noise_lookup)
990 for (
const auto& source : _world->getSimulationState().active_streaming_transmitters)
994 _cw_phase_noise_lookup = std::make_unique<simulation::CwPhaseNoiseLookup>(
1001 auto& t_current =
state.t_current;
1014 ensureCwPhaseNoiseLookup();
1016 while (t_current <
t_event && !isCancellationRequested())
1018 cleanupInactiveStreamingSources(t_current);
1038 emitContextHeartbeatsThrough(t_current);
1040 cleanupInactiveStreamingSources(t_current);
1043 std::optional<RealType> SimulationEngine::nextStreamingCleanupDeadline(
const RealType from_time)
1047 for (
const auto& source : active_streaming_transmitters)
1085 if (_output_sink !=
nullptr &&
t_step >= _next_context_heartbeat_time)
1087 emitContextHeartbeatsThrough(
t_step);
1091 reportSimulationProgress(
t_step);
1103 void SimulationEngine::appendReceiverStreamingSample(
const std::size_t
receiver_index,
1107 if ((
receiver_ptr->getMode() != OperationMode::CW_MODE &&
1108 receiver_ptr->getMode() != OperationMode::FMCW_MODE) ||
1121 else if (_output_sink !=
nullptr)
1135 block.push_back(sample);
1145 if (_eager_context_stream_open)
1155 block.push_back(sample);
1162 void SimulationEngine::flushStreamingOutputBlocks()
1226 else if (!dechirped)
1254 _streaming_downsamplers[
receiver_index] = std::make_unique<fers_signal::DownsamplingSink>();
1273 return if_plan.has_value() ?
if_plan->actual_output_sample_rate_hz : 0.0;
1282 void SimulationEngine::ensureStreamingOutputStreamOpen(
const std::size_t
receiver_index,
1315 void SimulationEngine::emitStreamingOutputBlock(
const std::size_t
receiver_index,
const RealType first_sample_time,
1317 const std::span<const ComplexType> samples,
1318 const std::uint64_t sample_start)
1327 processed.assign(samples.begin(), samples.end());
1332 ensureStreamingOutputStreamOpen(
receiver_index, first_sample_time, sample_rate);
1338 _streaming_output_sample_cursors[
receiver_index] = sample_start +
static_cast<std::uint64_t
>(
processed.size());
1343 if (_output_sink ==
nullptr)
1355 _next_context_heartbeat_time += 1.0;
1363 void SimulationEngine::flushFmcwIfBlocks()
1371 void SimulationEngine::flushFmcwIfBlock(
const std::size_t
receiver_index)
1394 void SimulationEngine::applyPulsedInterferenceToFmcwIfBlock(
const std::size_t
receiver_index,
1395 std::span<ComplexType>
block,
1403 void SimulationEngine::addPulsedInterferenceSamples(std::span<ComplexType>
block,
1421 if (!
mixer.has_value())
1434 void SimulationEngine::applyPulsedInterferenceToStreamingBlock(
const std::size_t
receiver_index,
1435 std::span<ComplexType>
block,
1445 if (!std::isfinite(sample_rate) || sample_rate <= 0.0)
1471 const auto dest_begin =
static_cast<long long>(
1473 const auto dest_end =
static_cast<long long>(std::min<RealType>(
1505 std::ranges::fill(
tracker_cache.dechirp_reference, FmcwChirpBoundaryTracker{});
1528 return std::nullopt;
1532 if (
rx->getDechirpMode() == Receiver::DechirpMode::Physical && _cw_phase_noise_lookup)
1555 : (
rx->getDechirpMode() == Receiver::DechirpMode::Ideal
1563 if (!
rx->checkFlag(Receiver::RecvFlag::FLAG_NODIRECT))
1593 void SimulationEngine::appendStreamingTrackerSource()
1597 for (
auto&
cache : _streaming_tracker_caches)
1599 cache.direct.emplace_back();
1604 void SimulationEngine::eraseStreamingTrackerSource(
const std::size_t
source_index)
1606 for (
auto&
cache : _streaming_tracker_caches)
1619 void SimulationEngine::cleanupInactiveStreamingSources(
const RealType from_time)
1635 sources.erase(
sources.begin() +
static_cast<std::ptrdiff_t
>(index));
1636 eraseStreamingTrackerSource(index);
1640 std::optional<RealType> SimulationEngine::streamingSourceCleanupDeadline(
const ActiveStreamingSource& source,
1643 if (source.transmitter ==
nullptr || source.carrier_freq <= 0.0)
1645 return std::nullopt;
1649 for (
const auto&
receiver_ptr : _world->getReceivers())
1661 std::optional<RealType> SimulationEngine::receiverCleanupDeadline(
const ActiveStreamingSource& source,
1667 return std::nullopt;
1685 return std::nullopt;
1688 std::optional<RealType>
latest;
1689 if (!
rx->checkFlag(Receiver::RecvFlag::FLAG_NODIRECT))
1693 for (
const auto&
target_ptr : _world->getTargets())
1750 void SimulationEngine::routeResponse(
Receiver*
rx, std::unique_ptr<serial::Response>
response)
const
1756 if (
rx->getMode() == OperationMode::PULSED_MODE)
1762 rx->addInterferenceToLog(std::move(
response));
1770 if (!
rx_ptr->checkFlag(Receiver::RecvFlag::FLAG_NODIRECT))
1792 rx->setActive(
true);
1798 rx->setActive(
false);
1799 const auto active_streaming_sources =
1800 collectStreamingSourcesForWindow(
t_event -
rx->getWindowLength(),
t_event);
1803 .duration =
rx->getWindowLength(),
1804 .responses =
rx->drainInbox(),
1805 .active_streaming_sources = active_streaming_sources};
1807 rx->enqueueFinalizerJob(std::move(
job));
1820 appendStreamingTrackerSource();
1833 rx->setActive(
true);
1835 { return receiver_ptr.get() == rx; });
1840 if (_eager_context_stream_open)
1846 if (
rx->hasFmcwIfResamplingSink())
1855 { return receiver_ptr.get() == rx; });
1867 if (
rx->hasFmcwIfResamplingSink())
1869 rx->endFmcwIfResamplingSegment();
1880 rx->setActive(
false);
1885 bool SimulationEngine::isCancellationRequested()
1891 if (_cancel_callback && _cancel_callback())
1894 LOG(Level::INFO,
"Simulation cancellation requested.");
1897 _reporter->report(
"Simulation cancelled", 100, 100);
1904 void SimulationEngine::reportSimulationProgress(
const RealType t_current)
1913 const RealType duration = end_time - start_time;
1915 const int progress =
static_cast<int>(
1918 if (
const auto now = std::chrono::steady_clock::now();
1919 progress != _last_reported_percent ||
now - _last_report_time >= std::chrono::milliseconds(100))
1921 _reporter->report(std::format(
"Simulating... {:.2f}s / {:.2f}s", t_current, end_time),
progress, 100);
1923 _last_report_time =
now;
1927 std::vector<ActiveStreamingSource> SimulationEngine::collectStreamingSourcesForWindow(
const RealType start_time,
1932 std::vector<ActiveStreamingSource>
sources;
1943 if (source.segment_start < source.segment_end && source.segment_start < end_time)
1963 void SimulationEngine::shutdown()
1965 LOG(Level::INFO,
"Simulation compute loop finished. Waiting for receiver finalization tasks...");
1968 _reporter->report(
"Simulation compute finished. Waiting for receiver finalization...", 100, 100);
1974 if (
receiver_ptr->getMode() == OperationMode::CW_MODE ||
1977 if (_output_sink !=
nullptr)
1989 else if (
receiver_ptr->getMode() == OperationMode::PULSED_MODE)
2006 LOG(Level::INFO,
"All finalization tasks complete.");
2010 const std::function<
void(
const std::string&,
int,
int)>& progress_callback,
2012 std::function<
bool()> cancel_callback,
bool* cancelled,
2015 if (cancelled !=
nullptr)
2019 auto reporter = std::make_shared<ProgressReporter>(progress_callback);
2020 auto metadata_collector = std::make_shared<OutputMetadataCollector>(output_dir);
2036 if (cancelled !=
nullptr)
2038 *cancelled =
engine.cancelled();
2042 LOG(Level::INFO,
"Waiting for VITA output stream drain...");
2043 reporter->report(
"Waiting for VITA output stream drain...", 100, 100);
2046 reporter->report(
engine.cancelled() ?
"Simulation cancelled" :
"Simulation complete", 100, 100);
2047 LOG(Level::INFO,
"Event-driven simulation loop finished.");
2048 auto metadata = metadata_collector->snapshot();
2054 if (stats.epoch_unix_nanoseconds.has_value())
2056 vita49_metadata.epoch_unix_nanoseconds = stats.epoch_unix_nanoseconds;
2058 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 FmcwTriangleSignal * getFmcwTriangleSignal() const noexcept
Gets the FMCW triangle implementation, if this signal owns one.
bool isFmcwFamily() const noexcept
Returns true when this signal belongs to the FMCW waveform family.
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.
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.
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.