Radar Data Generator — Statistical Detection Simulation
SkillDev toolsConfigure, simulate, debug, and analyze radarDataGenerator within radarScenario. Use for: interactively building radar detection scenarios from datasheets or performance requirements; diagnosing missed detections and configuration errors; interpreting sensor spherical, body, and scenario-frame outputs; deriving ReferenceRange from hardware specs via link budget; scan mode configuration (mechanical, electronic/AESA, hybrid); and validating simulation results against analytical predictions.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Radar Data Generator — Statistical Detection Simulation skill
What this skill tells your AI
The instructions your AI receives, as published by matlab/matlab-agentic-toolkit in skills-catalog/radar/matlab-simulate-radar-detections/SKILL.md and read by ahel’s review.
Build detection-level radar simulations using radarDataGenerator within radarScenario. This skill bridges user hardware specs and performance requirements to the Radar Toolbox statistical simulation API.
When to Use
- User wants to simulate radar detections on moving targets
- User has radar hardware specs (datasheet) or performance requirements and wants to build a simulation
- User mentions surveillance radar, scanning, revisit time, detection probability, or radar coverage
- User wants to compare scan strategies (mechanical vs electronic vs hybrid)
- User wants to generate detections to feed a tracker (trackerGNN, trackerJPDA) or do sensor fusion
- User wants Monte Carlo analysis, trade studies, or validation against link budget predictions
- User is studying radar placement or geometry to maximize coverage
- User has existing
radarDataGeneratorcode that isn't working — missed detections, configuration errors - User wants to validate simulation results against expected performance
When NOT to Use
- User needs I/Q-level waveform simulation (use
radarTransceiver+ pulse-Doppler chain) - User needs CFAR detector design or beamforming
- User needs waveform design (ambiguity functions, chirp optimization)
- User already has detections and wants to process them
- User needs bistatic or multistatic radar configurations
- User needs interference or jamming modeling (EW scenarios)
- User wants to call
radarDataGeneratorstandalone (withoutradarScenario) in a custom simulation loop
If the user needs signal-level fidelity, explain the tradeoff and hand off.
Detection Pathways
radarDataGenerator supports two detection pathways. This skill uses the target-pose pathway exclusively:
| Pathway | Call Signature | Detection Governed By | When Used |
|---|---|---|---|
| Target-pose (this skill) | detect(scenario) | DetectionProbability, FalseAlarmRate, ReferenceRange, ReferenceRCS | Standard radar simulation — targets defined as platforms with trajectories |
| Emissions | detect(scenario, propagatedEmissions) | Sensitivity, DetectionThreshold | ESM receivers, bistatic with explicit emission propagation |
Properties from one pathway have zero effect on the other. Setting Sensitivity or DetectionThreshold in the target-pose pathway produces a "not relevant" warning.
Standalone mode: radarDataGenerator can also be called outside a scenario: [dets, numDets, config] = rdg(targetPoses, simTime). Use for integration into custom loops (Simulink, event-driven). Loses advance(), trajectory automation, multi-sensor aggregation, and coverage visualization. See references/detection-model.md for the full standalone API and pose struct requirements.
Workflow
Follow these 9 steps interactively. Do NOT silently choose parameters — engage the user at each decision point.
Step 1: Recommend Approach
Recommend statistical-level simulation using radarDataGenerator within radarScenario. Explain the tradeoff: fast iteration on scenario design vs less control over signal processing. If user needs I/Q-level fidelity, name the alternative path (radarTransceiver + pulse-Doppler + CFAR) and stop the structured 9-step flow.
When they confirm statistical-level, state the approach and name the APIs: radarScenario, radarDataGenerator, platform, waypointTrajectory/kinematicTrajectory/geoTrajectory.
Step 2: Confirm Use Case
Suggest a use case (e.g., ground-based surveillance scanning a sector). Confirm:
- Scan type: Propose mechanical, offer electronic or both
- Coordinate frame: NED (default), ENU, or Earth-centered. State implications.
- Configuration: Confirm monostatic
- Propagation environment: Default is FreeSpace (no refraction). If user mentions long range, low-elevation targets, or over-the-horizon, offer atmosphere models:
atmosphere(scenario, model)—'EffectiveEarth'(4/3 radius),'RefractivityGradient', or'CRPL'. These add refraction bias to propagation paths (ray bending), affecting reported target positions — they do NOT add atmospheric attenuation to the link budget. Weather/precipitation is NOT modeled at statistical level.
Step 3: Ask Parameter Sourcing Direction
"Which direction are you working? Top-down (specify requirements, derive hardware)? Bottom-up (specify hardware, derive performance)? Or a mix?"
If user provides a datasheet: follow the datasheet ingestion procedure in references/coupled-parameters.md — extract parameters, map to groups, identify gaps, close link budgets, flag conflicts.
The flow branches here:
Top-down path (Steps 4 → 5): User specifies performance requirements first, then derive hardware.
- Step 4: Propose reference performance (range, RCS, Pd, Pfa)
- Step 5: Present coupled-parameter table, derive hardware needed to meet requirements
Bottom-up path (Steps 5 → 4): User specifies hardware first, then derive performance.
- Step 5: Present coupled-parameter table, collect hardware specs (power, gain, NF, bandwidth, etc.)
- Step 4: Derive and present reference performance from hardware via
radareqrng
Mixed/Datasheet: Collect what they have, fill gaps from both directions, flag inconsistencies.
Both paths converge at Step 6 (Target Set Design).
Step 4: Propose Reference Performance
Present as a reference target specification:
- Reference range, reference RCS (note:
ReferenceRCSis in dBsm) - Detection probability, false alarm rate (valid: [1e-7, 1e-3])
- Integration type and number of pulses (assume coherent; ask for N or CPI)
- Monostatic, clear sky
Top-down: Present concrete defaults. Let user react/modify.
Bottom-up: Present values derived from their hardware. Show the derivation (which function, which inputs). For integration: assume coherent, ask number of pulses or CPI duration. Use detectability(Pd, Pfa, 1, 'SwerlingN') - 10*log10(N) for required SNR. The Swerling argument is a string: 'Swerling0', 'Swerling1', ..., 'Swerling4'. Never pass N to detectability for coherent systems — that applies non-coherent loss. See references/interaction-flow.md § Step 4 for the full decision table.
Step 5: Present Coupled-Parameter Table
Show the parameter-relationship table from references/coupled-parameters.md. This builds confidence, shows traceability, invites correction.
Top-down: Use the table to derive what hardware is needed to meet the agreed reference performance. Bottom-up: Use the table to collect the user's hardware specs and identify which groups are constrained.
Step 6: Target Set Design
Confirm geometry (radar placement, scan sector, airborne targets). Propose physically representative targets varying:
- RCS (UAV ~0.01 m², fighter ~1 m², commercial ~10 m²)
- Speed (50 m/s rotary, 250 m/s jet, 300+ m/s fast mover)
- Altitude (500 m nap, 5 km mid, 10 km high)
Offer Swerling models (I = slow-fluctuating, III = dominant scatterer). Configure per-target RCS via rcsSignature on each platform's Signatures property — see references/detection-model.md for patterns. Default platform RCS is 10 dBsm (Swerling0).
Sanity checks before proceeding:
-
Verify target geometry is within radar horizon using
horizonrange(antennaHeight). If any target is beyond LOS at its specified altitude, flag this to the user. -
Compute the expected 0.9 Pd reference range for each target. Report a table like:
| Target | RCS (dBsm) | Swerling | Range (km) | Expected Pd |
|---|---|---|---|---|
| UAV | -20 | 1 | 15 | 0.72 |
| Fighter | 0 | 1 | 40 | 0.95 |
Use: SNR_at_R = RadarLoopGain + RCS_dBsm - 40*log10(range), then map SNR to Pd with the correct Swerling formula (see references/radar-equation-tools.md). Flag any target where expected Pd < 0.5 — the user should know which targets will have unreliable detection before running the sim.
Ask: "Do you need terrain or ground returns, or is free-space sufficient?"
Step 7: Terrain / Occlusion
If applicable — see references/terrain-clutter-atmosphere.md for terrain options. Terrain and occlusion are additive after validating detections in free-space. landSurface for height maps, seaSurface for sea state, customSurface for user-defined. landSurface has occlusion() for LOS blocking. HasOcclusion on radarDataGenerator is target-to-target occlusion.
Step 8: Simulation Duration
Ask in user's terms: seconds, number of scans, number of target illuminations, or event-based. Convert between these once scan parameters are locked.
Step 9: Produce Requirements Sheet
Generate a standalone document with three sections — see references/requirements-sheet-template.md.
Key Functions
| Function | Purpose | Toolbox |
|---|---|---|
radarScenario | Scenario container (platforms, time, detect) | Radar |
radarDataGenerator | Statistical detection sensor | Radar |
platform | Add platform to scenario | Radar |
waypointTrajectory | Waypoint-based motion in local coords (has ReferenceFrame) | Radar |
kinematicTrajectory | State-based motion in local coords (NO ReferenceFrame) | Radar |
geoTrajectory | Waypoint-based motion in geodetic coords (lat/lon/alt) — requires IsEarthCentered = true | Radar |
radareqrng | Max detection range from radar equation | Radar |
radareqpow | Required Tx power | Radar |
radareqsnr | Received SNR at range | Radar |
detectability | Required SNR (detectability factor) for Pd/Pfa/N/Swerling | Radar |
albersheim | Required SNR for Pd/Pfa/N (Swerling 0 only) | Phased Array |
shnidman | Required SNR for Pd/Pfa/N/Swerling 0–4 | Phased Array |
horizonrange | Radar horizon from antenna height | Radar |
height2el | Elevation angle from target height/range | Radar |
freq2wavelen | Wavelength from frequency | Phased Array |
rangeres2bw | Bandwidth from range resolution | Phased Array |
bw2rangeres | Range resolution from bandwidth | Phased Array |
speed2dop | Doppler shift from speed. One-way convention — for monostatic two-way: fd = 2*speed2dop(v, lambda) | Phased Array |
dop2speed | Speed from Doppler shift. One-way convention — for monostatic two-way: v = dop2speed(fd, lambda)/2 or use lambda*fd/2 directly | Phased Array |
beamwidth2gain | Antenna gain from half-power beamwidth. Must pass [azBW; elBW] column vector — scalar assumes symmetric beam. | Phased Array |
aperture2gain | Antenna gain from effective aperture | Phased Array |
gain2aperture | Effective aperture from antenna gain | Phased Array |
ap2beamwidth | Beamwidth from aperture length and wavelength | Phased Array |
beamwidth2ap | Aperture length from beamwidth and wavelength | Phased Array |
effbeamwidth | Two-way effective beamwidth (Tx+Rx) → maps to AzimuthResolution/ElevationResolution | Phased Array |
systemp | System noise temperature | Phased Array |
noisepow | Noise power from temperature + bandwidth | Phased Array |
theaterplot | Scenario visualization | Radar |
coverageConfig | Coverage diagram | Radar |
radarmetricplot | Plot metric vs range with objective/threshold lines and stoplight | Radar |
orientationPlotter | Visualize beam pointing direction (theaterPlot plotter) | Radar |
detectionPlotter | Visualize detections on theater plot | Radar |
landSurface | Static terrain (height matrix or DTED) — occlusion only with IsEarthCentered=true | Radar |
seaSurface | Dynamic ocean surface (spectral model, wind, fetch) | Radar |
customSurface | Polarization scattering matrix surface for clutter | Radar |
surfaceReflectivityLand | Land clutter reflectivity model (Barton, GIT, etc.) | Radar |
surfaceReflectivitySea | Sea clutter reflectivity model | Radar |
clutterGenerator | Add clutter to scenario (1:1 with radar sensor, requires a surface) | Radar |
ringClutterRegion | Define explicit clutter region (required when UseBeam=false) | Radar |
getClutterGenerator | Retrieve existing clutter generator for a radar | Radar |
Conventions
Traceability
- Every stochastic quantity traces to a configured parameter
radarDataGeneratorprovides built-in traceability — property names ARE the documentation- If hand-rolling any computation, comment the model, its parameters, and how it connects to system design
Coordinate Frames
- Pick ONE frame and use it consistently throughout
waypointTrajectoryhas'ReferenceFrame'property:'NED'or'ENU'— use withIsEarthCentered = falsekinematicTrajectoryhas NOReferenceFrame— inherits from scenario — use withIsEarthCentered = falsegeoTrajectoryuses geodetic waypoints [lat, lon, alt] in [deg, deg, m] — requiresIsEarthCentered = true- Has
'ReferenceFrame'('NED'/'ENU') for velocity/orientation interpretation - Also supports
Course,GroundSpeed,ClimbRateas alternatives toVelocities DetectionCoordinates = 'Scenario'reports in ECEF (meters), not lat/lon- Single waypoint = stationary platform (TimeOfArrival is ignored)
- Has
- Constraint: trajectory type and
IsEarthCenteredare strictly coupled — mixing produces an error - NED: elevation is negative above horizon. ENU: elevation is positive above.
- Always validate: compute expected elevation analytically, compare to measured
Parameter Source Tags
Every parameter in the requirements sheet gets a tag:
- User-provided — they told us
- Domain assumption — reasonable default, justified
- Derived — computed from other params (show which function)
System Parameters vs Simulation Parameters
Once the user's requirements and use case are confirmed (Steps 2–6), distinguish between:
- System parameters (user's design): FieldOfView, CenterFrequency, Bandwidth, MaxAzimuthScanRate, ReferenceRange, antenna height, etc. Never change these to fix a simulation issue.
- Simulation parameters (our configuration): UpdateRate, RangeLimits, scenario UpdateRate, DetectionCoordinates, simulation duration. These can be tuned freely.
If a simulation artifact occurs (e.g., missed detections due to beam stepping), fix it by adjusting simulation parameters. If the fix requires changing a system parameter, surface it to the user with physical intuition — it's a design insight, not a sim fix.
Self-Consistency
After deriving all parameters, validate the loop closes:
- Compute Rmax from hardware via
radareqrng - Configure
ReferenceRange= Rmax - Run simulation, confirm ~Pd at reference range
- If mismatch, diagnose and flag
Common Mistakes
| Mistake | Why It's Wrong | Correct Approach |
|---|---|---|
Changing non-tunable properties without release() | radarDataGenerator is a System object — non-tunable properties (FieldOfView, ScanMode, AzimuthResolution, scan limits) are locked after first call to detect() | Call release(radar) before modifying non-tunable properties, then restart(scenario) before re-running |
ReferenceRCS in linear m² | Property expects dBsm | Convert: 10*log10(rcs_linear) |
range2bw / bw2range | Deprecated | Use rangeres2bw / bw2rangeres |
MechanicalScanLimits | Does not exist | Use MechanicalAzimuthLimits, MechanicalElevationLimits |
Setting MaxAzimuthScanRate for electronic scan | Ignored (warning issued) | Beam steps by FieldOfView(1) per update in electronic mode |
Confusing detect(scenario) with detect(platform, time) | Different signatures — scenario-level returns all sensors' detections combined | dets = detect(scenario) or [dets, configs] = detect(scenario) — both valid. Per-platform: [dets, ~, configs] = detect(platform, time) |
| Forgetting elevation sign in NED | Targets above horizon have negative elevation | Check sign: el = -asind(alt/range) in NED |
HasScanLoss with non-Custom scan | Only applies when ScanMode='Custom' | Omit for Mechanical/Electronic modes |
| Mixing trajectory reference frames | Causes silent position errors | Set all waypointTrajectory objects to same 'ReferenceFrame' |
waypointTrajectory shorter than StopTime | Scenario stops at max trajectory endpoint, NOT at StopTime. Platform goes to NaN position after trajectory ends — silently stops being detected. | Extend all waypointTrajectory endpoints to >= StopTime (add hold waypoint). Or use kinematicTrajectory for constant-velocity platforms. |
Confusing radar/waypointTrajectory with drivingScenario trajectories | Different API — drivingScenario uses actor waypoints, not this class | In radarScenario, always use waypointTrajectory, kinematicTrajectory, or geoTrajectory |
Using kinematicTrajectory for a moving platform with a forward-looking sensor | Body frame orientation is FIXED (default: identity = scenario axes). Does NOT rotate with velocity — a forward-looking sensor will not track the flight path. | Use waypointTrajectory or geoTrajectory for moving platforms with sensors. Their body frame rotates with heading. |
Hardcoded noise (e.g., 0.2*randn) | Not traceable, breaks self-consistency | Use radarDataGenerator built-in noise model or comment the source |
Not setting sensor UpdateRate | Default is 1 Hz — scan rate = FoV(1)*1 = crawl | Always set 'UpdateRate' explicitly on radarDataGenerator |
Scenario UpdateRate < sensor UpdateRate | Aliasing: only a fraction of FoV dwell positions are sampled. Targets between sampled positions get zero detections silently. | Set scenario UpdateRate = sensor UpdateRate for detection-complete sims. |
| Comparing sensor rectangular measurements directly to scenario-frame truth | Sensor rectangular is a beam-rotating frame — each detection's coordinate system depends on where the beam was pointing at detection time. Raw measurements will differ from truth by tens of km. | Use per-detection MeasurementParameters(1): scenarioPos = Orientation * Measurement + OriginPosition. The Orientation matrix encodes mounting + current scan angle. |
| Assuming spherical measurement order is [range, az, el] | Actual order is [az, el, range] for 'Sensor spherical' | Check DetectionCoordinates setting; default is 'Body' (Cartesian) |
Not setting RangeLimits | Default is [0, 100 km] — targets beyond 100 km silently produce no detections | Set 'RangeLimits', [0, R] where R = max(maxTargetRange, ReferenceRange * 1.2) |
Using 'Sector' with MechanicalElevationLimits | 'Sector' sets HasElevation=false — elevation limits are ignored (warning issued) | Use explicit 'ScanMode','Mechanical' with HasElevation=true if elevation scanning is needed |
Setting or investigating HasElevation for detection issues | HasElevation does NOT affect whether targets are detected. It only controls whether elevation angle is measured and whether the beam scans in elevation. Default is false (azimuth-only). | Never set HasElevation=false (it's already the default). Never investigate HasElevation when debugging missing detections — it cannot cause them. Missing detections are caused by: RangeLimits, target outside scan sector, insufficient ReferenceRange/ReferenceRCS, or UpdateRate too low. |
Calling atmosphere(scene, model) with IsEarthCentered=false | Errors: "The IsEarthCentered property must be true to modify the atmosphere model" | All atmosphere/refraction models require IsEarthCentered=true. Flat-earth scenarios are always free-space. |
Expecting terrain to block targets with IsEarthCentered=false | Terrain occlusion in detect() only works with IsEarthCentered=true | If terrain masking matters, use earth-centered scenario with geoTrajectory |
Confusing HasOcclusion with terrain occlusion | HasOcclusion is target-to-target (extended objects); terrain LOS is via SurfaceManager | For terrain masking: IsEarthCentered=true + landSurface. For target-to-target: HasOcclusion=true |
clutterGenerator without any surface | Produces 0 clutter detections silently | Add landSurface(scene) or seaSurface(scene) before creating clutter generator |
ScattererDistribution='RangeDopplerCells' with radarDataGenerator | Error at detect() | Only works with radarTransceiver; use 'Uniform' (default) for radarDataGenerator |
UseBeam=false without ringClutterRegion | 0 clutter detections | Add explicit regions: ringClutterRegion(cg, minR, maxR, azSpan, azCenter) |
Setting Sensitivity or DetectionThreshold in target-pose mode | "Not relevant" — these are emissions-pathway only | In the target-pose pathway (detect(scenario)), detection is governed solely by Pd/Pfa/ReferenceRange/ReferenceRCS |
Increasing FalseAlarmRate to simulate surface clutter | FalseAlarmRate produces uniformly distributed false detections (white noise); it does not model spatially correlated surface clutter with realistic sigma-zero, geometry, or Doppler | Use clutterGenerator with a surface (landSurface/seaSurface) and reflectivity model. See terrain-clutter-atmosphere.md. |
Expecting radarDataGenerator to model signal processing losses (MTI, STAP, CFAR) | The statistical model does not simulate clutter-rejection filter losses, STAP adaptive weight losses, or detectability degradation near the clutter ridge in range-Doppler space | These effects require I/Q-level simulation (Phased Array System Toolbox waveform + receiver chain). For statistical-level approximation, add expected processing losses via the Loss parameter in the link budget (radareqsnr), or reduce DetectionProbability in clutter-affected regions. |
dop2speed(1/CPI, lambda) for monostatic velocity resolution | Gives 2× correct value (3.0 m/s instead of 1.5 m/s) | dop2speed uses one-way convention. Monostatic velocity resolution = lambda/(2*CPI). Either use manual formula or dop2speed(fd,lambda)/2. |
radareqrng(SNR, lambda, ...) — wrong arg order | Silent wrong answer (no error) | Correct: radareqrng(lambda, SNR, Pt, tau, ...) — lambda first |
Passing Gain in linear to radareqrng | Absurd range (10^49 km) | Gain is dBi, not linear. Pass 30, not 1000. |
Passing RCS in dBsm to radareqrng | Wrong by 3× or errors on negative | RCS is linear m². Convert: db2pow(rcs_dBsm) |
Passing average power to radareqrng as Pt | Underestimates range | Pt is peak power (Watts). Derive: Ppeak = Pavg / (tau * PRF) |
Using FieldOfView for antenna gain derivation | Wrong gain when FoV ≠ beamwidth | Gain comes from beamwidth2gain([AzimuthResolution; ElevationResolution]). Both beamwidths required — scalar input assumes symmetric beam (up to 10 dB error for fan beams). FoV is the angular coverage per scan position; it is not necessarily equal to the receive beamwidth. |
Assuming FieldOfView must equal AzimuthResolution | Incorrect scan step for AESA or wide-Tx configurations | FoV and resolution are independent. FoV = Tx beamwidth (typical). For shared aperture, FoV = AzRes. For wide Tx + narrow Rx, FoV > AzRes. |
| Applying Swerling I Pd formula to a default (Swerling0) target | Underpredicts Pd by ~40% at reference range (0.52 vs 0.89) | Check target.Signatures{1}.FluctuationModel. Default is Swerling0 — use marcumq. For Swerling1 targets: Pfa^(1/(1+SNR_lin)). |
Scan Mode Quick Reference
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 1k
- Forks
- 128
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
matlab-simulate-radar-detections- Source
- github.com/matlab/matlab-agentic-toolkit