Simulation Pipeline
This page describes how a simulation flows from configuration to output.
Pipeline Stages
config.json
│
▼
┌─────────┐
│ Config │ load_config() parses JSON
└────┬─────┘
│
▼
┌──────────┐
│ Geometry │ Layer placement, r0 profile, wind profile
└────┬─────┘
│
▼
┌─────────┐
│ Layers │ Phase screen initialization (Von Karman, autoregressive)
└────┬────┘
│
▼
┌────────────┐
│ Propagator │ Precompute transfer functions for angular spectrum method
└────┬───────┘
│
▼
┌───────────┐
│ Time Loop │ Propagate → Record → Extrude (repeat for N steps)
└────┬──────┘
│
▼
┌────────┐
│ Output │ (steps, 2, nx_size, nx_size) frames
└────────┘
Stage Details
1. Configuration
load_config() reads config.json and returns a nested dictionary. All leaf parameters use the {"value": ..., "description": ...} format.
2. Geometry
The Geometry dataclass (core/geometry/geometry.py) constructs the atmospheric model:
- Cn2 profile: Hufnagel-Valley model with parameter
Asolved from the user-specified totalr0viasolve_for_A()(usesscipy.optimize.fsolve) - Layer placement: Heights are chosen so each layer contributes equally to the fractional scintillation index (integrates
Cn2(h) * h^(5/6)) - r0 profile: Per-layer Fried parameters computed from the Cn2 profile
- Wind profile: Bufton wind model; satellite slew rate contributes to effective wind at each layer height
3. Layers
Each layer wraps a PhaseScreenVonKarman -- an infinite-length phase screen generated via autoregressive row extrusion:
- Initial screen: Created using
ft_sh_phase_screen()(FFT-based with subharmonic compensation) - Autoregressive model: Uses pre-computed
A_matandB_matmatrices. New rows are generated as:new_row = A_mat @ stencil_data + B_mat @ random_noise - GPU conversion:
GpuLayerwraps the NumPy arrays astf.Variableandtf.constantfor use in@tf.function
4. Propagator
The Propagator class (core/propagation/propagator.py) implements the angular spectrum method for Fresnel propagation:
- Precomputes quadratic phase factors
Q1,Q2,Q3and magnification factors per layer - All NumPy arrays are pre-converted to TF tensors at init time (
tf_Q1,tf_Q2,tf_Q3,tf_m,tf_deltaf,tf_delta,tf_sg) to avoid baking Python/NumPy constants into the graph during@tf.functiontracing - Applies a super-Gaussian window (
exp(-r^16)) to suppress edge artifacts - Downlink geometry: Reverses the layer order and recalculates propagation distances to model satellite-to-ground direction
5. Time Loop
At each time step:
- Propagate: A flat unit-amplitude wavefront passes through all layers via the angular spectrum method
- Record: The output complex field is decomposed into phase (
angle(Uout)) and amplitude (abs(Uout)) - Extrude: Each layer advances by
v_wind * dt / pixel_scalepixel rows, generating new turbulence via the autoregressive model
6. Output
The recorded frames are collected into a (steps, 2, nx_size, nx_size) array and saved to disk. See Output Format for details.
Downlink Geometry
The simulator models satellite-to-ground propagation:
- The beam originates at the satellite (highest layer) and propagates downward
- Layer order is reversed internally so propagation proceeds from high altitude to ground
- Propagation distances account for the zenith angle:
distance = height / cos(zenith) - The satellite orbit altitude determines the starting range and slew rate contribution to wind