FERS 0.1.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
finalizer_pipeline.h
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2//
3// Copyright (c) 2026-present FERS Contributors (see AUTHORS.md).
4//
5// See the GNU GPLv2 LICENSE file in the FERS project root for more information.
6
7/**
8 * @file finalizer_pipeline.h
9 * @brief Declares focused, testable pipeline steps for receiver finalization.
10 *
11 * This header defines the individual, single-responsibility functions that
12 * constitute the signal processing pipeline for both pulsed and continuous-wave
13 * receivers. By breaking the finalization process into these discrete steps,
14 * each function becomes highly cohesive, easier to understand, and independently
15 * testable.
16 */
17
18#pragma once
19
20#include <cstddef>
21#include <memory>
22#include <span>
23#include <string>
24#include <tuple>
25#include <vector>
26
27#include "core/config.h"
29
30namespace timing
31{
32 class Timing;
33}
34namespace radar
35{
36 class Receiver;
37 class Transmitter;
38 class Target;
39}
40namespace serial
41{
42 class Response;
43}
44namespace core
45{
46 struct OutputFileMetadata;
47}
48namespace simulation
49{
50 struct CwPhaseNoiseLookup;
51}
52
54{
55 /// Half-open sample span used for dechirped LO-active finalization ranges.
57 {
58 std::size_t start = 0; ///< Inclusive first sample index in the span.
59 std::size_t end_exclusive = 0; ///< Exclusive sample index at the end of the span.
60 };
61
62 /**
63 * @brief Advances the receiver's timing model to the start of the next processing window.
64 *
65 * This function handles the "dead time" between receive windows. For sync-on-pulse
66 * models, it resets the phase and skips to the window's start offset. For
67 * free-running models, it skips the number of samples corresponding to the
68 * inter-pulse period.
69 *
70 * @param timing_model The stateful timing model instance to advance.
71 * @param receiver The receiver whose properties (sync mode, PRF, etc.) determine how to advance the model.
72 * @param rate The oversampled simulation rate, used to calculate samples to skip.
73 */
75
76 /**
77 * @brief Calculates the jittered start time and fractional delay from a phase noise sample.
78 *
79 * Converts the first phase noise sample (in radians) of a window into a time
80 * jitter offset. It then decomposes the resulting "actual" start time into a
81 * component aligned with the sample clock and a fractional delay to be handled
82 * by the rendering engine's interpolation filter.
83 *
84 * @param ideal_start The perfect, jitter-free start time of the window.
85 * @param first_phase_noise The first phase noise sample (radians) for this window.
86 * @param carrier_freq The carrier frequency, needed to convert phase to time.
87 * @param rate The sampling rate, used for sample clock alignment.
88 * @return A tuple containing:
89 * 1. The sample-aligned start time (RealType).
90 * 2. The fractional sample delay (RealType).
91 */
93 RealType carrier_freq, RealType rate);
94
95 /**
96 * @brief Applies streaming interference to a time window.
97 *
98 * Iterates through each sample of a processing window, calculating the combined
99 * direct and reflected path contributions from all active streaming sources at that
100 * precise moment in time. The resulting complex sample is added to the window.
101 *
102 * @param window The I/Q buffer for the receive window to which interference will be added.
103 * @param actual_start The jittered, sample-aligned start time of the window.
104 * @param dt The time step between samples (1.0 / rate).
105 * @param receiver The receiver being interfered with.
106 * @param streaming_sources A list of currently active streaming transmitters.
107 * @param targets The list of all targets for calculating reflected paths.
108 * @param tracker_cache Caller-owned reusable tracker storage for FMCW path boundary state.
109 */
110 void applyStreamingInterference(std::span<ComplexType> window, RealType actual_start, RealType dt,
112 const std::vector<core::ActiveStreamingSource>& streaming_sources,
113 const std::vector<std::unique_ptr<radar::Target>>* targets,
115 const simulation::CwPhaseNoiseLookup* phase_noise_lookup = nullptr);
116
117 /**
118 * @brief Renders and applies pulsed interference to a streaming IQ buffer.
119 *
120 * Processes a log of `Response` objects that represent pulsed signals received
121 * during a streaming receiver's operation. Each response is rendered into a temporary
122 * buffer and then added to the main streaming IQ buffer at the correct time offset.
123 *
124 * @param iq_buffer The main, simulation-long IQ buffer for the streaming receiver.
125 * @param interference_log A list of `Response` objects representing the pulsed interference.
126 */
127 void applyPulsedInterference(std::vector<ComplexType>& iq_buffer,
128 const std::vector<std::unique_ptr<serial::Response>>& interference_log);
129
130 /**
131 * @brief Renders and applies pulsed interference only inside active sample spans.
132 *
133 * @param iq_buffer The main, simulation-long IQ buffer for the streaming receiver.
134 * @param interference_log A list of `Response` objects representing the pulsed interference.
135 * @param active_spans Half-open sample spans where LO-active output should receive interference.
136 * @param output_sample_rate The sample rate used by `iq_buffer`, in hertz.
137 */
138 void applyPulsedInterference(std::vector<ComplexType>& iq_buffer,
139 const std::vector<std::unique_ptr<serial::Response>>& interference_log,
140 std::span<const SampleSpan> active_spans, RealType output_sample_rate);
141
142 /**
143 * @brief Applies a pre-generated sequence of phase noise samples to an I/Q buffer.
144 *
145 * This function performs the complex multiplication `IQ_out = IQ_in * e^(j*phase_noise)`
146 * for each sample in the window, effectively modulating the phase of the signal.
147 *
148 * @param noise A span of phase noise samples in radians.
149 * @param window The I/Q buffer to be modified.
150 */
151 void addPhaseNoiseToWindow(std::span<const RealType> noise, std::span<ComplexType> window);
152
153 /**
154 * @brief Downsamples and quantizes an IQ buffer.
155 *
156 * This function performs the final processing steps. If oversampling is enabled,
157 * it first downsamples the buffer to the final output rate. It then simulates
158 * an ADC by quantizing and scaling the data.
159 *
160 * @param buffer The I/Q buffer to be processed. This is an in-out parameter; it will
161 * be replaced by the downsampled buffer if applicable.
162 * @return The full-scale value (RealType) calculated during quantization, which is
163 * needed for HDF5 metadata.
164 */
165 RealType applyDownsamplingAndQuantization(std::vector<ComplexType>& buffer);
166
167 /**
168 * @brief Downsamples an IQ buffer to the configured output rate without quantization.
169 *
170 * This is used by streaming output sinks that must apply their own fixed-scale
171 * quantization after all producer-side physics, interference, and noise are complete.
172 *
173 * @param buffer The I/Q buffer to downsample in place when oversampling is configured.
174 */
175 void applyDownsampling(std::vector<ComplexType>& buffer);
176
177 /**
178 * @brief Exports a finalized streaming IQ buffer to an HDF5 file.
179 *
180 * Creates an HDF5 file, splits the complex buffer into real (I) and imaginary (Q)
181 * components, writes them as separate datasets, and adds relevant simulation
182 * parameters (sample rate, start time, etc.) as file attributes.
183 *
184 * @param filename The path to the output HDF5 file.
185 * @param iq_buffer The final, processed I/Q data to write.
186 * @param fullscale The full-scale value from quantization, saved as metadata.
187 * @param ref_freq The reference carrier frequency, saved as metadata.
188 * @param metadata Optional structured output metadata to attach to the file.
189 * @param sample_rate Output sample rate to store in the file, or `params::rate()` when unset.
190 */
191 void exportStreamingToHdf5(const std::string& filename, const std::vector<ComplexType>& iq_buffer,
192 RealType fullscale, RealType ref_freq,
193 const core::OutputFileMetadata* metadata = nullptr, RealType sample_rate = 0.0);
194
195}
const Receiver & receiver
Manages radar signal reception and response processing.
Definition receiver.h:47
Represents a timing source for simulation.
Definition timing.h:36
Global configuration file for the project.
double RealType
Type for real numbers.
Definition config.h:27
void applyStreamingInterference(std::span< ComplexType > window, const RealType actual_start, const RealType dt, const radar::Receiver *receiver, const std::vector< core::ActiveStreamingSource > &streaming_sources, const std::vector< std::unique_ptr< radar::Target > > *targets, core::ReceiverTrackerCache &tracker_cache, const simulation::CwPhaseNoiseLookup *phase_noise_lookup)
Applies streaming interference to a time window.
void addPhaseNoiseToWindow(std::span< const RealType > noise, std::span< ComplexType > window)
Applies a pre-generated sequence of phase noise samples to an I/Q buffer.
RealType applyDownsamplingAndQuantization(std::vector< ComplexType > &buffer)
Downsamples and quantizes an IQ buffer.
void advanceTimingModel(timing::Timing *timing_model, const radar::Receiver *receiver, const RealType rate)
Advances the receiver's timing model to the start of the next processing window.
std::tuple< RealType, RealType > calculateJitteredStart(const RealType ideal_start, const RealType first_phase_noise, const RealType carrier_freq, const RealType rate)
Calculates the jittered start time and fractional delay from a phase noise sample.
void applyPulsedInterference(std::vector< ComplexType > &iq_buffer, const std::vector< std::unique_ptr< serial::Response > > &interference_log)
Renders and applies pulsed interference to a streaming IQ buffer.
void exportStreamingToHdf5(const std::string &filename, const std::vector< ComplexType > &iq_buffer, const RealType fullscale, const RealType ref_freq, const core::OutputFileMetadata *metadata, const RealType sample_rate)
Exports a finalized streaming IQ buffer to an HDF5 file.
void applyDownsampling(std::vector< ComplexType > &buffer)
Downsamples an IQ buffer to the configured output rate without quantization.
math::Vec3 max
Defines the global state for the event-driven simulation engine.
Metadata for one receiver output file.
Per-receiver FMCW tracker state for direct and reflected streaming paths.
Half-open sample span used for dechirped LO-active finalization ranges.
std::size_t start
Inclusive first sample index in the span.
std::size_t end_exclusive
Exclusive sample index at the end of the span.
Lookup table for CW phase noise across timing sources.