VirtualInstrument

DeepSpaceTelemetry.VirtualInstrumentModule
VirtualInstrument

Science-payload data source: amplitude-calibrated synthetic LISA strain via windowed overlap-add FFT synthesis against the sky-averaged LISA sensitivity of Robson, Cornish & Liu (2019), or gapless segmented ingestion of an external CSV time series.

source
DeepSpaceTelemetry.VirtualInstrument.InstrumentStateType
InstrumentState

Maintains the state of the satellite's scientific payload. Can generate synthetic LISA strain noise (instrument sensitivity plus the galactic-confusion foreground, lisa_noise_psd) or ingest an externally provided continuous 1D time-series CSV array.

Synthetic strain is generated by a windowed overlap-add (WOLA) scheme: amplitude-calibrated colored-noise blocks of 2N samples (N = samples per segment) are shaped with a periodic sqrt-Hann window and summed at 50% overlap. The squared window tiles to exactly 1, so the emitted stream is stationary, continuous across segment boundaries, and reproduces the sky-averaged LISA sensitivity with the correct absolute amplitude (spectral content below 1/(2·segment_duration_sec) Hz is not representable at this block length — increase segment_duration_sec for low-frequency fidelity). The constructor keywords confusion_observation_years (0.5, 1.0, 2.0, or 4.0) select the confusion fit and noise_f_min_hz the lower edge of the synthesized band: bins below it, the DC bin included, carry no power, so the model is never evaluated outside its domain.

The amplitude spectrum is stored in Float64: raw LISA PSD values (~1e-40) underflow into Float32 subnormals.

All stochastic draws (noise phases) come from the instrument's own rng (any Random.AbstractRNG; default Xoshiro(0)), seeded via the constructor keyword — the stream is fully reproducible from simulation.rng_seed and independent of the global RNG and of other simulation components.

The struct is deliberately named differently from its parent module: an exported struct sharing the module's name shadows the module binding in downstream using scopes, breaking qualified access (VirtualInstrument.next_segment!).

source
DeepSpaceTelemetry.VirtualInstrument.lisa_noise_psdFunction
lisa_noise_psd(f; observation_years = 1.0) -> Float64

Sky-averaged LISA sensitivity [Hz⁻¹] at frequency f [Hz]: the instrument term lisa_instrument_psd plus the galactic-confusion foreground lisa_confusion_psd of the fit for observation_years. It is the noise PSD divided by the sky- and polarization-averaged response (Robson, Cornish & Liu 2019, Eqs. 1 and 14), the quantity the downstream classifier whitens against, and the synthesis reproduces it at the correct absolute level. Returns Inf for f ≤ 0; the synthesis zeroes the DC bin and every bin below noise_f_min_hz, so no floor value can enter a stream.

source
DeepSpaceTelemetry.VirtualInstrument.welch_psdFunction
welch_psd(x::AbstractVector{<:Real}, fs::Real; nperseg = 0) -> (Vector{Float64}, Vector{Float64})

One-sided power spectral density of x sampled at fs [Hz], by Welch's method: Hann windows of nperseg samples (default: the largest power of two giving at least eight segments, floored at 256) overlapping by half, each segment mean-removed, the periodograms averaged and normalized so the estimate integrates to the variance of the series. Returns the frequency grid and the density in units of /Hz.

The measurement counterpart of lisa_noise_psd: a stream synthesized from S(f) returns it over the band its synthesis block resolves, which is what the payload-spectrum figure shows. Below 1/(2·segment_duration_sec) the estimate carries spectral leakage, not content — no power was synthesized there.

Returns empty vectors when x is shorter than one window.

source
DeepSpaceTelemetry.VirtualInstrument.lisa_instrument_psdFunction
lisa_instrument_psd(f) -> Float64

Sky- and polarization-averaged LISA instrument sensitivity S_n(f) [Hz⁻¹] at frequency f [Hz], Robson, Cornish & Liu (2019) Eq. 1:

S_n(f) = 10 / (3 L²) · [P_OMS(f) + 2 (1 + cos²(f/f*)) P_acc(f) / (2π f)⁴] · [1 + 0.6 (f/f*)²]

with P_OMS = (1.5 × 10⁻¹¹)² (1 + (2 mHz / f)⁴) m² Hz⁻¹, P_acc = (3 × 10⁻¹⁵)² (1 + (0.4 mHz / f)²) (1 + (f / 8 mHz)⁴) m² s⁻⁴ Hz⁻¹ (the constants OMS_NOISE_AMPLITUDE, OMS_NOISE_KNEE_HZ, ACCELERATION_NOISE_AMPLITUDE, ACCELERATION_NOISE_LOW_KNEE_HZ, ACCELERATION_NOISE_HIGH_KNEE_HZ, and RESPONSE_CORRECTION_COEFFICIENT), L = 2.5 × 10⁹ m, and f* = c / (2π L). This is the noise PSD divided by the sky-averaged response, the quantity a strain stream is whitened against. Returns Inf for f ≤ 0.

source
DeepSpaceTelemetry.VirtualInstrument.lisa_confusion_psdFunction
lisa_confusion_psd(f, observation_years = 1.0) -> Float64

Unresolved galactic-binary confusion foreground S_c(f) [Hz⁻¹] at frequency f [Hz], Robson, Cornish & Liu (2019) Eq. 14:

S_c(f) = A f^(-7/3) exp(-f^α + β f sin(κ f)) [1 + tanh(γ (f_k − f))]

with A = CONFUSION_AMPLITUDE and (α, β, κ, γ, f_k) from CONFUSION_FITS for observation_years (one of 0.5, 1.0, 2.0, 4.0; ArgumentError otherwise). Returns Inf for f ≤ 0.

The product is evaluated in log space with log(1 + tanh(x)) = log 2 − softplus(−2x): far above the knee f_k the cutoff factor underflows to zero while exp(β f sin(κ f)) can overflow, and the direct product would give NaN where the foreground is zero.

source
DeepSpaceTelemetry.VirtualInstrument.synth_windowed_blockFunction
synth_windowed_block(rng::AbstractRNG, noise_amp::Vector{Float64}, window::Vector{Float64})

Synthesizes one sqrt-Hann-windowed block of amplitude-calibrated colored noise of length(window) samples from the scaled amplitude spectrum noise_amp (see InstrumentState), drawing phases from rng. The DC bin is zeroed and the Nyquist bin is forced real, as required for a real-valued signal. Allocating convenience form of synth_windowed_block!.

source
DeepSpaceTelemetry.VirtualInstrument.synth_windowed_block!Function
synth_windowed_block!(block, z, irfft_plan, rng, noise_amp, window)

In-place core of synth_windowed_block: draws the spectral realization into z, applies the cached irfft_plan, and writes the windowed block into block. Allocation-free apart from the transform's internal workspace; the RNG draw order is identical to the allocating form, so seeded streams are unchanged.

source
DeepSpaceTelemetry.VirtualInstrument.next_segment!Function
next_segment!(vi::InstrumentState)

Produces the next temporal segment of science data, either sliced from the external array or synthesized as calibrated noise. Synthetic segments are phase-continuous across calls: each segment is the sum of the previous block's overlap-add tail and the head of a freshly synthesized windowed block (see InstrumentState).

source