Writing scenarios¶
A scenario is a YAML (or JSON) file with up to six sections. Everything is optional
except a radar and at least the targets you want; anything left out takes the default
in the tables below. Unknown keys are not silently dropped: the loader lists them as
warnings, with a suggestion when the key looks like a typo
(rain_rate_mmhr → rain_rate_mm_hr).
Coordinates are East-North-Up in metres with the origin anywhere you like (usually the radar). Azimuths are degrees clockwise from North. See Conventions.
A minimal file:
scenario:
name: "Two aircraft"
radar:
frequency_hz: 3.0e9
power_watts: 200000
antenna: {gain_db: 35, beamwidth_az_deg: 1.5, scan_rate_rpm: 12}
targets:
- name: "Inbound"
affiliation: hostile
rcs_m2: 5
initial_position: {x_m: 20000, y_m: 60000, z_m: 4000}
velocity: {vx_mps: -100, vy_mps: -250, vz_mps: 0}
The fastest way to start a new one is the scenario editor, which writes this format.
scenario¶
| Key | Default | Meaning |
|---|---|---|
name |
Unnamed Scenario |
shown in the header |
description |
one or two sentences | |
duration_seconds |
180 | used by the command-line runner |
update_rate_hz |
30 | engine steps per simulated second |
seed |
none | random seed (also accepted under simulation) |
radar¶
| Key | Default | Meaning |
|---|---|---|
name |
Radar |
|
type |
free text, informational | |
frequency_hz |
10e9 | carrier |
power_watts |
100e3 | peak power |
prf_hz |
1000 | pulse repetition frequency |
pulse_width_s |
1e-6 | transmitted pulse length |
system_losses_db |
4 | two-way losses |
position |
origin | {x_m, y_m, z_m} |
height_above_terrain_m |
if set (and terrain exists), the antenna is placed this high above the ground at position |
|
velocity |
0 | {vx_mps, vy_mps, vz_mps} for airborne or ship radars |
radar.antenna
| Key | Default | Meaning |
|---|---|---|
gain_db |
30 | |
beamwidth_az_deg, beamwidth_el_deg |
2, 3 | 3 dB beamwidths |
sidelobe_db |
−30 | one-way sidelobe floor, used for clutter entering through the elevation pattern |
polarization_tilt_deg |
0 | 0 = horizontal, 90 = vertical |
scan_type |
circular |
circular, sector or stare |
scan_rate_rpm / scan_rate_deg_s |
6 rpm | rotation rate (circular) |
sector_az_min_deg, sector_az_max_deg |
−60, 60 | sector limits |
scan_speed_deg_s |
rpm × 6 | sector raster speed |
stare_azimuth_deg |
0 | pointing in stare mode |
radar.receiver
| Key | Default | Meaning |
|---|---|---|
noise_figure_db |
4 | |
bandwidth_hz |
1/pulse width | noise bandwidth; τ·B > 1 means pulse compression |
system_temperature_k |
290 | |
full_scale_dbm |
−20 | hard-limiter level |
dynamic_range_db |
alternative to full_scale_dbm: full scale = kTBF + dynamic range |
targets¶
A list; each entry:
| Key | Default | Meaning |
|---|---|---|
name |
Target_n |
|
type |
aircraft |
free text (fighter, missile, ship, …) |
affiliation |
unknown |
friend, hostile, neutral, unknown (display only) |
rcs_m2 |
1 | mean RCS |
swerling_model |
1 | 0–4 |
initial_position |
origin | {x_m, y_m, z_m}, z = altitude |
velocity |
0 | {vx_mps, vy_mps, vz_mps} |
acceleration |
0 | {ax_mps2, ay_mps2, az_mps2}: constant acceleration |
turn_rate_deg_s |
0 | constant-rate turn, positive = right |
deploy_time_s |
0 | appears at this time |
has_ecm |
false | carries a jammer |
ecm_type |
noise_barrage |
noise_barrage, noise_spot, drfm |
ecm_power_watts |
1000 | jammer ERP |
ecm_bandwidth_hz |
100e6 | noise bandwidth |
drfm |
{mode: rgpo|vgpo, gain_over_skin_db, capture_dwell_s, pull_rate_mps, max_pull_m, vgpo_rate_hz_per_s, max_doppler_pull_hz, inherent_delay_s} |
ecm¶
Expendables released during the run. With deployed_by they start at that target's
position at deploy_time_s; otherwise give a position.
ecm:
decoys:
- name: "MALD"
deployed_by: "F-16 Alpha"
deploy_time_s: 30
velocity: {vx_mps: 300, vy_mps: 30, vz_mps: -5}
rcs_m2: 5
chaff_clouds:
- name: "Chaff 1"
deployed_by: "F-16 Alpha"
deploy_time_s: 60
rcs_m2: 50 # fully bloomed
bloom_time_s: 1 # rise time constant
decay_time_s: 120 # dispersal time constant
A decoy without its own velocity keeps the carrier's velocity; chaff without one
falls at 1 m/s.
environment¶
| Key | Default | Meaning |
|---|---|---|
temperature_c |
15 | |
pressure_hpa |
1013.25 | barometric (total) pressure |
water_vapor_gpm3 |
7.5 | |
rain_rate_mm_hr |
0 | |
rain_height_m |
3360 | top of the rain layer (ITU-R P.839) |
terrain_type |
rural |
surface class for clutter: urban, suburban, rural, forest, desert, mountain, sea |
sea_state |
0 | Douglas 0–6 |
ground_surface |
{model: gamma|oh1992, gamma_db, relative_permittivity_real, relative_permittivity_loss, rms_height_m} |
|
clutter.velocity_spread_mps |
land 0.25, sea 1.0 | clutter spectrum width for the MTI improvement factor |
clutter.sectors |
list of {name, azimuth_start_deg, azimuth_end_deg, range_start_km, range_end_km, terrain_type, sigma0_adjustment_db}; the first sector containing a cell wins |
|
terrain |
{preset: flat|mountainous|ambush} or a custom relief {seed, scale_m, max_height_m, octaves, persistence, lacunarity, peaks: [{x_m, y_m, height_m}]} |
When terrain is given, heights in the file are above mean sea level.
simulation¶
| Key | Default | Meaning |
|---|---|---|
enable_atmospheric_loss |
true | |
enable_clutter |
false | surface and rain clutter |
pfa |
1e-6 | false-alarm probability per cell |
pulses_integrated |
1 | non-coherently integrated pulses per look |
range_noise_std_m |
50 | measurement noise |
angle_noise_std_rad |
0.001 | measurement noise (when monopulse is off) |
scan_gated_detection |
true | look only when the beam passes; false = every step |
cfar |
off | {type: CA|GO|SO|OS, reference_cells, guard_cells} |
mti |
off | {enabled, threshold_mps} |
monopulse |
off | {enabled} |
eccm |
{frequency_agility} |
|
tracker |
{process_noise_mps2: 10, confirm_hits: 3, max_misses: 3} |
|
seed |
none | random seed for a reproducible run |