Generated banner for Matlab Simulate Radar Detections
Generated logo for Matlab Simulate Radar Detections

Matlab Simulate Radar Detections

MathWorksOfficialCreated by MathWorks

  • Skill
  • Tool integration
  • Software development
  • BSD-2-Clause
  • No issues found

From the author

Configure, 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.
— the description by MathWorks

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a structured 9-step workflow to build and debug statistical-level radar simulations using the radarDataGenerator within a radarScenario. It bridges hardware specifications and performance requirements to the Radar Toolbox simulation API, enabling users to perform trade studies, validate detection performance, and diagnose configuration errors in radar placement or scan strategies.

What it does

  • Guides users through a 9-step process to build radar detection simulations.
  • Maps hardware specifications to simulation parameters using coupled-parameter relationships.
  • Supports top-down (requirements-to-hardware) and bottom-up (hardware-to-performance) design paths.
  • Provides diagnostic support for common simulation issues like missed detections and coordinate frame errors.
  • Facilitates validation of simulation results against analytical link budget predictions.
  • Generates a structured requirements sheet for documentation and traceability.

When to use it

  • When you need to simulate radar detections on moving targets for surveillance or tracking.
  • When you have radar hardware specs or performance requirements and need to build a simulation.
  • When you need to compare scan strategies like mechanical, electronic, or hybrid modes.
  • When you need to validate radar placement or geometry to maximize coverage.
  • When you have existing radarDataGenerator code that is producing unexpected results.

Advantages

  • Fast iteration on scenario design compared to signal-level simulation.
  • Built-in traceability between stochastic quantities and configured parameters.
  • Clear separation between system design parameters and simulation-specific settings.
  • Provides analytical tools to verify loop closure between hardware specs and simulation output.
  • Includes comprehensive diagnostic checks for common pitfalls like coordinate frame mismatches.

Usage examples

“I need to simulate a ground-based surveillance radar. How do I start?”
The agent will initiate the 9-step workflow, starting with Step 1 to confirm the statistical-level simulation approach and identifying the necessary APIs like radarScenario and radarDataGenerator.
“My radar is missing detections at long range. How can I debug this?”
The agent will guide you through checking simulation parameters like RangeLimits, UpdateRate, and ReferenceRange, and verify if the target is within the radar horizon using horizonrange.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/matlab/matlab-simulate-radar-detections/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip matlab-simulate-radar-detections.zip -d .agents/skills

Documentation by MathWorks

Radar Data Generator — Statistical Detection Simulation

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 radarDataGenerator code 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 radarDataGenerator standalone (without radarScenario) 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:

PathwayCall SignatureDetection Governed ByWhen Used
Target-pose (this skill)detect(scenario)DetectionProbability, FalseAlarmRate, ReferenceRange, ReferenceRCSStandard radar simulation — targets defined as platforms with trajectories
Emissionsdetect(scenario, propagatedEmissions)Sensitivity, DetectionThresholdESM 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: ReferenceRCS is 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:

  1. 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.

  2. Compute the expected 0.9 Pd reference range for each target. Report a table like:

TargetRCS (dBsm)SwerlingRange (km)Expected Pd
UAV-201150.72
Fighter01400.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

FunctionPurposeToolbox
radarScenarioScenario container (platforms, time, detect)Radar
radarDataGeneratorStatistical detection sensorRadar
platformAdd platform to scenarioRadar
waypointTrajectoryWaypoint-based motion in local coords (has ReferenceFrame)Radar
kinematicTrajectoryState-based motion in local coords (NO ReferenceFrame)Radar
geoTrajectoryWaypoint-based motion in geodetic coords (lat/lon/alt) — requires IsEarthCentered = trueRadar
radareqrngMax detection range from radar equationRadar
radareqpowRequired Tx powerRadar
radareqsnrReceived SNR at rangeRadar
detectabilityRequired SNR (detectability factor) for Pd/Pfa/N/SwerlingRadar
albersheimRequired SNR for Pd/Pfa/N (Swerling 0 only)Phased Array
shnidmanRequired SNR for Pd/Pfa/N/Swerling 0–4Phased Array
horizonrangeRadar horizon from antenna heightRadar
height2elElevation angle from target height/rangeRadar
freq2wavelenWavelength from frequencyPhased Array
rangeres2bwBandwidth from range resolutionPhased Array
bw2rangeresRange resolution from bandwidthPhased Array
speed2dopDoppler shift from speed. One-way convention — for monostatic two-way: fd = 2*speed2dop(v, lambda)Phased Array
dop2speedSpeed from Doppler shift. One-way convention — for monostatic two-way: v = dop2speed(fd, lambda)/2 or use lambda*fd/2 directlyPhased Array
beamwidth2gainAntenna gain from half-power beamwidth. Must pass [azBW; elBW] column vector — scalar assumes symmetric beam.Phased Array
aperture2gainAntenna gain from effective aperturePhased Array
gain2apertureEffective aperture from antenna gainPhased Array
ap2beamwidthBeamwidth from aperture length and wavelengthPhased Array
beamwidth2apAperture length from beamwidth and wavelengthPhased Array
effbeamwidthTwo-way effective beamwidth (Tx+Rx) → maps to AzimuthResolution/ElevationResolutionPhased Array
systempSystem noise temperaturePhased Array
noisepowNoise power from temperature + bandwidthPhased Array
theaterplotScenario visualizationRadar
coverageConfigCoverage diagramRadar
radarmetricplotPlot metric vs range with objective/threshold lines and stoplightRadar
orientationPlotterVisualize beam pointing direction (theaterPlot plotter)Radar
detectionPlotterVisualize detections on theater plotRadar
landSurfaceStatic terrain (height matrix or DTED) — occlusion only with IsEarthCentered=trueRadar
seaSurfaceDynamic ocean surface (spectral model, wind, fetch)Radar
customSurfacePolarization scattering matrix surface for clutterRadar
surfaceReflectivityLandLand clutter reflectivity model (Barton, GIT, etc.)Radar
surfaceReflectivitySeaSea clutter reflectivity modelRadar
clutterGeneratorAdd clutter to scenario (1:1 with radar sensor, requires a surface)Radar
ringClutterRegionDefine explicit clutter region (required when UseBeam=false)Radar
getClutterGeneratorRetrieve existing clutter generator for a radarRadar

Conventions

Traceability
  • Every stochastic quantity traces to a configured parameter

  • radarDataGenerator provides 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

  • waypointTrajectory has 'ReferenceFrame' property: 'NED' or 'ENU' — use with IsEarthCentered = false

  • kinematicTrajectory has NO ReferenceFrame — inherits from scenario — use with IsEarthCentered = false

  • geoTrajectory uses geodetic waypoints [lat, lon, alt] in [deg, deg, m] — requires IsEarthCentered = true

    • Has 'ReferenceFrame' ('NED'/'ENU') for velocity/orientation interpretation

    • Also supports Course, GroundSpeed, ClimbRate as alternatives to Velocities

    • DetectionCoordinates = 'Scenario' reports in ECEF (meters), not lat/lon

    • Single waypoint = stationary platform (TimeOfArrival is ignored)

  • Constraint: trajectory type and IsEarthCentered are 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

MistakeWhy It's WrongCorrect 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 dBsmConvert: 10*log10(rcs_linear)
range2bw / bw2rangeDeprecatedUse rangeres2bw / bw2rangeres
MechanicalScanLimitsDoes not existUse MechanicalAzimuthLimits, MechanicalElevationLimits
Setting MaxAzimuthScanRate for electronic scanIgnored (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 combineddets = detect(scenario) or [dets, configs] = detect(scenario) — both valid. Per-platform: [dets, ~, configs] = detect(platform, time)
Forgetting elevation sign in NEDTargets above horizon have negative elevationCheck sign: el = -asind(alt/range) in NED
HasScanLoss with non-Custom scanOnly applies when ScanMode='Custom'Omit for Mechanical/Electronic modes
Mixing trajectory reference framesCauses silent position errorsSet all waypointTrajectory objects to same 'ReferenceFrame'
waypointTrajectory shorter than StopTimeScenario 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 trajectoriesDifferent API — drivingScenario uses actor waypoints, not this classIn radarScenario, always use waypointTrajectory, kinematicTrajectory, or geoTrajectory
Using kinematicTrajectory for a moving platform with a forward-looking sensorBody 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-consistencyUse radarDataGenerator built-in noise model or comment the source
Not setting sensor UpdateRateDefault is 1 Hz — scan rate = FoV(1)*1 = crawlAlways set 'UpdateRate' explicitly on radarDataGenerator
Scenario UpdateRate < sensor UpdateRateAliasing: 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 truthSensor 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 RangeLimitsDefault is [0, 100 km] — targets beyond 100 km silently produce no detectionsSet '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 issuesHasElevation 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=falseErrors: "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=falseTerrain occlusion in detect() only works with IsEarthCentered=trueIf terrain masking matters, use earth-centered scenario with geoTrajectory
Confusing HasOcclusion with terrain occlusionHasOcclusion is target-to-target (extended objects); terrain LOS is via SurfaceManagerFor terrain masking: IsEarthCentered=true + landSurface. For target-to-target: HasOcclusion=true
clutterGenerator without any surfaceProduces 0 clutter detections silentlyAdd landSurface(scene) or seaSurface(scene) before creating clutter generator
ScattererDistribution='RangeDopplerCells' with radarDataGeneratorError at detect()Only works with radarTransceiver; use 'Uniform' (default) for radarDataGenerator
UseBeam=false without ringClutterRegion0 clutter detectionsAdd explicit regions: ringClutterRegion(cg, minR, maxR, azSpan, azCenter)
Setting Sensitivity or DetectionThreshold in target-pose mode"Not relevant" — these are emissions-pathway onlyIn the target-pose pathway (detect(scenario)), detection is governed solely by Pd/Pfa/ReferenceRange/ReferenceRCS
Increasing FalseAlarmRate to simulate surface clutterFalseAlarmRate produces uniformly distributed false detections (white noise); it does not model spatially correlated surface clutter with realistic sigma-zero, geometry, or DopplerUse 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 spaceThese 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 resolutionGives 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 orderSilent wrong answer (no error)Correct: radareqrng(lambda, SNR, Pt, tau, ...) — lambda first
Passing Gain in linear to radareqrngAbsurd range (10^49 km)Gain is dBi, not linear. Pass 30, not 1000.
Passing RCS in dBsm to radareqrngWrong by 3× or errors on negativeRCS is linear m². Convert: db2pow(rcs_dBsm)
Passing average power to radareqrng as PtUnderestimates rangePt is peak power (Watts). Derive: Ppeak = Pavg / (tau * PRF)
Using FieldOfView for antenna gain derivationWrong gain when FoV ≠ beamwidthGain 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 AzimuthResolutionIncorrect scan step for AESA or wide-Tx configurationsFoV 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) targetUnderpredicts 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

ModeKey Behavior
'Mechanical'actualRate = min(FieldOfView(1) * sensorUpdateRate, MaxAzimuthScanRate). See scan rate model below.
'Electronic'Beam steps by FieldOfView(1) per update. MaxAzimuthScanRate irrelevant.
'Mechanical and electronic'Mechanical provides coarse pointing, electronic refines.
'No scanning'Fixed staring beam.

Convenience constructors: radarDataGenerator(id, 'Raster'), 'Rotator', 'Sector', 'Custom'.

Mechanical Scan Rate Model (Critical)

The actual scan rate for mechanical mode is:

actualScanRate = min(FieldOfView(1) * sensorUpdateRate, MaxAzimuthScanRate)  [deg/s]
stepPerScenarioUpdate = actualScanRate / scenarioUpdateRate  [deg]

Default sensor UpdateRate is 1 Hz. If not set explicitly, a 2-deg beam scans at only 2 deg/s regardless of MaxAzimuthScanRate. Always set sensor UpdateRate explicitly:

radar = radarDataGenerator(1, 'Sector', ...
    'UpdateRate', 20, ...  % MUST set — default 1 Hz causes very slow scan
    'FieldOfView', [2; 20], ...
    'MaxAzimuthScanRate', 36, ...
    ...);
% actualRate = min(2*20, 36) = 36 deg/s ✓

To achieve a desired scan rate with a narrow beam:

  • sensorUpdateRate >= desiredRate / FieldOfView(1)

  • Example: 36 deg/s with 2-deg beam needs UpdateRate >= 18 Hz

Scenario vs Sensor UpdateRate

The sensor fires at its own UpdateRate; the scenario UpdateRate controls how often advance()/detect() execute. If scenario rate < sensor rate, only a fraction of dwell positions are sampled — targets between sampled positions produce zero detections silently.

Rule: Always set scenario UpdateRate = sensor UpdateRate unless you specifically want sparse detection cadence.

Detection Model

SNR = RadarLoopGain + RCS_dBsm - 40*log10(Range)
  • RadarLoopGain: read-only, derived from ReferenceRange + ReferenceRCS + DetectionProbability + FalseAlarmRate. The reference SNR uses Swerling0 (non-fluctuating) internally — target fluctuation models are applied separately at detection time.

  • No hardware knobs (Pt, Gain, NF) — all lumped into reference performance

  • CenterFrequency/Bandwidth affect resolution only, not detection range

  • Measurement accuracy: σ² = (Δ/√(2·SNR))² + (BiasFraction·Δ)² — Cramér-Rao plus bias floor. Defaults: AzimuthBiasFraction=0.1, RangeBiasFraction=0.05, ElevationBiasFraction=0.1. At high SNR the bias floor dominates (0.3° azimuth, 3.75m range).

  • Pd vs range depends on target FluctuationModel — default platforms are Swerling0 (non-fluctuating). Use marcumq for Swerling0, Pfa^(1/(1+SNR)) for Swerling1. Using the wrong formula gives ~40% Pd error. See references/radar-equation-tools.md for the full recipe.

The agent's job is to bridge between user hardware specs and this statistical interface using radar equation tools as the translation layer.

Troubleshooting

SymptomLikely CauseDiagnostic / Fix
No detections at allRangeLimits too shortCheck radar.RangeLimits(2) >= max target range
No detections at allSensor UpdateRate = 1 Hz (default)Beam scanning too slowly — set UpdateRate explicitly
No detections at all (UpdateRate is set)Scenario UpdateRate < sensor UpdateRateFoV dwell aliasing — only sampled positions produce detections. Set scenario UpdateRate = sensor UpdateRate.
No detections at allTarget outside beam FoVUse coverageConfig(radar) to get current beam direction; compare to target bearing
Detections only on some scansTarget near beam step boundaryNormal for mechanical scan — fast targets at bearings aligned with beam step positions may be missed on some sweeps. Increase sensor/scenario UpdateRate to reduce step size (never change system parameters like FieldOfView to fix a simulation artifact).
Too many detectionsSelf-detection (radar platform)Filter: ignore detections where TargetIndex == radar platform ID (usually 1)
Pd much lower than configuredTarget beyond ReferenceRangeSNR drops as 40·log10(R) — expected; Pd is specified AT reference range only
Pd higher than expectedTarget RCS > ReferenceRCSHigher RCS increases SNR — check rcsSignature on target platform
Empirical Pd > 1.0Dividing detections by scans, not illuminationsMechanical scan is bidirectional: illuminations = 2 × scans for sector scan. Count beam passes from IsScanDone or compute from scan timing: nIlluminations = StopTime / (sector / scanRate).
Measured position far from truthPlotting raw .Measurement against scenario-frame truthMust convert to scenario frame first. Use MeasurementParameters.Orientation and .OriginPosition to transform. "0 azimuth" = sensor boresight, not north. See API Answer Key for conversion recipes.
Range-limited vs LOS-limitedTargets beyond radar horizonUse horizonrange(antennaHeight) to check. Comment in code where missed detections are expected due to LOS. This should also be caught as a sanity check before writing code (Step 6 — verify target geometry is within radar horizon).
Self-consistency check failsHardware-derived Rmax ≠ configured ReferenceRangeRecheck radareqrng inputs match the hardware specs fed to the derivation
Programmatic Verification

Detection accuracy check — verify measurement errors are within expected bounds. This must account for DetectionCoordinates mode — raw .Measurement values cannot be compared to scenario-frame truth unless using 'Scenario' mode:

% Convert detection to scenario frame FIRST (required for all non-Scenario modes)
mp = dets{k}.MeasurementParameters(1);  % first element = position transform
meas = dets{k}.Measurement;
switch mp.Frame
    case 'Spherical'
        az = meas(1); el = meas(2); R = meas(3);
        posSensor = [R*cosd(el)*cosd(az); R*cosd(el)*sind(az); R*sind(el)];
        measScenario = mp.Orientation * posSensor + mp.OriginPosition(:);
    case 'Rectangular'
        measScenario = mp.Orientation * meas(1:3)' + mp.OriginPosition(:);
end
posError = norm(measScenario - truthPos);
expectedSigma = sqrt(trace(dets{k}.MeasurementNoise(1:3,1:3)));
assert(posError < 5*expectedSigma, 'Position error exceeds 5-sigma');

SNR check — verify reported SNR matches link budget prediction (within ~1 dB):

expectedSNR = radar.RadarLoopGain + rcs_dBsm - 40*log10(slantRange);
reportedSNR = dets{k}.ObjectAttributes{1}.SNR;
assert(abs(reportedSNR - expectedSNR) < 1.0, 'SNR mismatch > 1 dB');

See Coordinates & Transforms — Verification for full mode-aware verification patterns.

Debugging: Isolate Beam Pointing

When diagnosing "no detections" or unexpected detection gaps, isolate whether the problem is beam pointing vs. something else:

  1. Release the sensor, then go omnidirectional:

origFoV = radar.FieldOfView;
origScan = radar.ScanMode;
release(radar);
radar.FieldOfView = [360; 180];
radar.ScanMode = 'No scanning';
  1. Restart and re-run the scenario (restart(scenario) + advance loop)

  2. Interpret:

    • Detections appear → problem is beam pointing (scan limits, MountingAngles, FoV, scan stepping over target)

    • Still no detections → problem is elsewhere (RangeLimits, UpdateRate aliasing, ReferenceRange, horizon, target RCS)

  3. Release and restore original config before continuing:

release(radar);
radar.FieldOfView = origFoV;
radar.ScanMode = origScan;

Note: radarDataGenerator is a System object. Non-tunable properties (FieldOfView, ScanMode, AzimuthResolution, scan limits, etc.) cannot be changed after detect() has been called without first calling release(radar). Always release() before modifying non-tunable properties.

Do this BEFORE drilling into individual parameters — it splits the problem space in half with one test.

Debugging Order
  1. Omnidirectional isolation (above) — rules out beam pointing in one test

  2. Inspect systematic causes — RangeLimits gate, scan sector bounds, UpdateRate aliasing. These produce deterministic failures (0% Pd) and are identifiable from a single run.

  3. Monte Carlo trials (last) — only after systematic causes are ruled out. Use repeated runs to characterize stochastic behavior: Swerling fluctuation, intermittent detections near the detection boundary, empirical Pd vs analytical Pd. Never run Monte Carlo to diagnose a target that gets 0 detections — that is always a systematic cause.

Fix Forward: Step Hierarchy

When validation fails, fix the latest step that could be wrong. Never change a system parameter (Steps 1–5) to accommodate a scenario choice (Steps 6–7). If the radar's FoV doesn't cover a target, the target is out of coverage — don't widen FoV to "fix" it. Only revisit earlier steps when there is a genuine design error.

Analyzing Simulation Outputs

Critical NED traps that cause silent errors:

  • Geometric elevation (positive up): atand(-dx(3) ./ horizRange) — negate D-axis so airborne targets get positive angle. Sensor spherical elevation has opposite sign for NED (sensor +z = Down): airborne targets get negative el.

  • Azimuth: atan2d(East, North) — swapping arguments gives azimuth from East (90° error)

  • Empirical Pd: platformID = targetIndex + 1 (radar is platform 1) — off-by-one is common

  • Analytical Pd: Default is Swerling0 (marcumq), not Swerling I — using wrong formula gives 40% error

  • SNR: RadarLoopGain + RCS_dBsm - 40*log10(R) — do NOT add integration gain (already in RLG)

See Coordinates & Transforms for full conversion recipes and verification patterns.

Output Requirements

  1. Requirements sheet — standalone document (see template in references)

  2. MATLAB script — runnable, with design-rationale comments and coupled-parameter table

  3. Validation — compare simulation detections to analytical predictions

Code Generation Rules
  • Never rely on defaults for radarDataGenerator. Set every relevant property explicitly in the constructor, even when using the default value. This makes the code self-documenting — a reader should see every parameter choice without consulting documentation. Hidden defaults are hidden assumptions. Exception — property gating: Do NOT set properties that are irrelevant to the current configuration. Setting gated properties produces warnings ("not relevant in this configuration"). See the property-gating table below.

  • Tag each parameter value with its source: user-provided, derived (from which inputs), or domain assumption (with justification).

Property-Gating Rules

Properties gated by Has* flags — do NOT set these when the flag is false:

Gate (when false)Do NOT set
HasElevationElevationResolution, ElevationBiasFraction, MaxElevationScanRate, MechanicalElevationLimits, ElectronicElevationLimits
HasRangeRateRangeRateResolution, RangeRateBiasFraction, RangeRateLimits, HasRangeRateAmbiguities
HasRangeAmbiguitiesMaxUnambiguousRange
HasRangeRateAmbiguitiesMaxUnambiguousRadialSpeed

Properties gated by ScanMode:

ScanModeDo NOT set
'No scanning'MaxAzimuthScanRate, MaxElevationScanRate, MechanicalAzimuthLimits, MechanicalElevationLimits, ElectronicAzimuthLimits, ElectronicElevationLimits
'Mechanical'ElectronicAzimuthLimits, ElectronicElevationLimits
'Electronic'MechanicalAzimuthLimits, MechanicalElevationLimits, MaxAzimuthScanRate, MaxElevationScanRate
'Mechanical and electronic'(all scan properties valid)

Never set HasScanLoss — it warns in all scan modes (not valid in any current configuration).

When EmissionsInputPort=true: do NOT set ScanMode, FieldOfView, or any scan-limit/rate properties (scan is driven by emissions).

Properties gated by TargetReportFormat:

FormatDo NOT set
'Clustered detections' or 'Detections'FilterInitializationFcn, ConfirmationThreshold, DeletionThreshold, TrackCoordinates
'Tracks'DetectionCoordinates

Properties gated by DetectionMode:

ModeDo NOT set
'ESM'ReferenceRange, ReferenceRCS, DetectionProbability

References

Load only what the task requires — do not read all references for every prompt.

ReferenceWhen to Read
Detection ModelConfiguring radar properties, debugging property names, understanding detection pathway
FoV & ScanSetting FieldOfView, scan mode config, UpdateRate/scan rate derivation
Coordinates & TransformsInterpreting detections, converting frames, NED elevation/azimuth, plotting
TrajectoriesTarget motion, stationary platforms, scenario duration, body frame orientation
Terrain, Clutter & AtmosphereAdding surfaces, clutter generator, atmosphere models, occlusion
Radar Equation ToolsBottom-up derivation, hardware-to-ReferenceRange bridge, Pd vs range
VisualizationtheaterPlot, coverage plots, radarmetricplot
Coupled ParametersStep 5: parameter-relationship table, datasheet ingestion
Interaction FlowFull 9-step workflow with suggested phrasings
Requirements Sheet TemplateStep 9: three-section output artifact structure

Copyright 2026 The MathWorks, Inc.

Files

references/coupled-parameters.md

Coupled Parameters

Present this table to the user during Step 5 of the workflow. It shows which parameters are coupled, what the relationship is, and which Radar Toolbox API computes the conversion.

Parameter-Relationship Table

GroupParameters (pick what you know)RelationshipAPI / Function
FrequencyCenter frequency ↔ wavelengthλ = c / ffreq2wavelen (Phased Array)
Antenna gainGain ↔ beamwidth (az, el)Narrower beam → higher gainbeamwidth2gain([azBW; elBW]) (Phased Array) — must pass both dimensions as column vector
Antenna gainGain ↔ effective apertureLarger aperture → higher gain (freq-dependent)aperture2gain(A, lambda) / gain2aperture(G, lambda) (Phased Array)
Antenna sizeAperture length ↔ beamwidthLarger aperture → narrower beam (freq-dependent)ap2beamwidth(d, lambda) / beamwidth2ap(hpbw, lambda) (Phased Array)
Angular resolutionTx beamwidth + Rx beamwidth → effectiveTwo-way 3 dB width narrower than either aloneeffbeamwidth(θTx, θRx) → AzimuthResolution / ElevationResolution (Phased Array)
PowerPeak power ↔ average power ↔ duty cyclePavg = Ppeak × dutyManual: Pavg = Pt * tau * PRF
TimingPulse width ↔ PRF/PRI ↔ duty cycleduty = τ × PRFManual: duty = tau * PRF; PRI = 1/PRF
TimingPulse width → minimum range (blind zone)Rmin = c·τ/2 (uses actual pulse width, not 1/BW)Manual: Rmin = physconst('LightSpeed')*tau/2. Suggest as RangeLimits(1) when τ is known.
ResolutionBandwidth → range resolutionΔR = c/(2·BW). BW is independent of τ for modulated pulses.rangeres2bw / bw2rangeres (Phased Array)
NoiseNoise figure ↔ system temperatureTs = T0·(NF−1)systemp(NF_dB) (Phased Array)
DopplerSpeed ↔ Doppler shiftfd_twoway = 2v/λ (monostatic)speed2dop/dop2speed use one-way convention (fd = v/λ). For monostatic: fd_twoway = 2*speed2dop(v,lambda) or v = dop2speed(fd_twoway,lambda)/2. Velocity resolution: deltaV = lambda/(2*CPI) — do NOT pass 1/CPI to dop2speed directly.
DopplerPRF → max unambiguous velocityVmax = λ·PRF/4Manual: vMax = lambda*PRF/4
Range ambiguityPRF → max unambiguous rangeRunamb = c/(2·PRF)Manual: rUnamb = physconst('LightSpeed')/(2*PRF)
IntegrationNcoh + Nnoncoh + PRF → dwell timeTdwell = Ncpi·(Ncoh·Nnoncoh)/PRFManual; maps to radarDataGenerator.UpdateRate = 1/Tdwell
IntegrationNcoh → coherent gainGcoh = 10·log10(Ncoh) dBManual: -pow2db(Ncoh) in detectability decomposition
ScanScan rate + sector + FoV → revisit timeTrevisit = 2·sector/scanRate (bidirectional)Manual; actualScanRate = min(FoV(1)*UpdateRate, MaxAzimuthScanRate). Note: FoV is the dwell extent (scan step), not the beamwidth.
DetectionHardware → reference range via detectabilityD01 + Gci + Lcustom (no Lf)detectability, radareqrng, radareqsnr (Radar)
HorizonAntenna height → radar horizonGeometric + refractionhorizonrange (Radar)

How to Use This Table

  1. Present it to the user after they've stated their known parameters (Step 5)

  2. For each group, mark which parameter(s) the user knows

  3. Derive the unknowns using the listed API or manual formula

  4. Flag any inconsistencies:

    • duty cycle AND pulse width AND PRF must be self-consistent: duty = tau * PRF

    • PRF vs max range: Runamb = c/(2*PRF) must exceed ReferenceRange. If not, the radar has range ambiguities — surface this to the user as a design constraint, not silently proceed.

    • Tau vs min range: Rmin = c*tau/2 is the blind zone. If user specifies targets below this, they can't be detected.

    • Peak power, average power, duty cycle: only 2 of 3 are independent

  5. Tag each derived value with its source in the requirements sheet

Bridging Hardware to radarDataGenerator

radarDataGenerator has no hardware knobs. The bridge is the detectability decomposition (matches the radarDesigner export pattern):

Step-by-step
  1. Collect hardware specs: Pt (peak, Watts), G (dBi), NF (dB), Losses (dB), τ (seconds), PRF (Hz), BW (Hz), fc (Hz), Ncoh, Nnoncoh, Swerling case. τ is mandatory — it determines pulse energy (E = Pt × τ) and is a required positional argument to radareqrng. If not stated: derive from duty cycle (tau = duty/PRF). Do NOT assume tau = 1/BW unless user confirms an unmodulated pulse (TBP = 1). When both τ and BW are stated and tau*BW > 1, flag the time-bandwidth product as pulse compression ratio.

  2. Compute detectability components:

    D01     = detectability(Pd, Pfa, 1, 'Swerling0');       % baseline single-pulse
    Lf      = detectability(Pd, Pfa, Nnoncoh, Sw) - ...
              detectability(Pd, Pfa, Nnoncoh, 'Swerling0'); % fluctuation loss
    Gci     = -pow2db(Ncoh);                                % coherent integration gain (negative dB)
    Lcustom = systemLosses_dB;                              % implementation/system losses
  3. Compute threshold for ReferenceRange (exclude fluctuation loss):

    thresholdSNR = D01 + Gci + Lcustom;  % NO Lf — RDG applies Swerling internally
  4. Compute max range via radareqrng:

    Rmax = radareqrng(lambda, thresholdSNR, Pt, tau, ...
        'Gain', G_dBi, 'Ts', Ts, 'Loss', Lcustom, 'RCS', rcs_linear);
  5. Configure radarDataGenerator:

    • ReferenceRange = Rmax

    • ReferenceRCS = reference target in dBsm

    • DetectionProbability and FalseAlarmRate = same Pd/Pfa used in step 2

    • RangeLimits = [0, max(maxTargetRange, Rmax*1.2)]

  6. Verify: RadarLoopGain (read-only) now encodes all hardware implicitly

Processing Gain (User-Facing Definition)

When users say "processing gain," they mean the total SNR improvement beyond a single pulse. Map it to the decomposition:

processingGain_dB = -Gci - Lcustom = 10*log10(Ncoh) - systemLosses_dB

More precisely, processing gain is everything that improves SNR beyond the single-pulse baseline:

  • Coherent integration gain: 10*log10(Ncoh) dB (always positive)

  • Non-coherent integration gain: handled inside detectability(Pd, Pfa, N, Sw) — reduces required per-pulse SNR

  • Minus system losses: implementation losses reduce effective gain

In radareqrng, processing gain enters via the 'CustomFactor' Name-Value pair (positive dB = helps) or by reducing the SNR argument. Both approaches are equivalent.

Critical Rule

ReferenceRange must be computed WITHOUT fluctuation loss. The radarDataGenerator applies Swerling fluctuation internally at detection time. Including Lf in the threshold produces a pessimistic (too-short) reference range that double-counts fluctuation.

Key Insight

The statistical API lumps all hardware into reference performance. The radar equation tools (radareqrng, radareqpow, radareqsnr) and the detection probability function (detectability) are the translation layer between hardware specs and the statistical interface.

Ambiguity Properties and Limit Gating

HasRangeAmbiguities and HasRangeRateAmbiguities have asymmetric pipelines:

Range: Gate Then Fold
True range → RangeLimits gates on TRUE range → HasRangeAmbiguities folds REPORTED range
StepWhat happens
1. RangeLimitsAccepts/rejects based on true target range
2. MaxUnambiguousRangeFolds the reported position: mod(trueRange, MaxUnambiguousRange)

A target at 50 km with RangeLimits=[0, 80e3] and MaxUnambiguousRange=30e3 passes the gate (50 < 80) and reports at 20 km (mod 30). The same target with RangeLimits=[0, 29e3] is rejected before folding ever applies.

Range Rate: Fold Then Gate
True radial speed → HasRangeRateAmbiguities folds into [-MaxUnambiguousRadialSpeed, +Max] → RangeRateLimits gates on FOLDED speed
StepWhat happens
1. MaxUnambiguousRadialSpeedWraps velocity into unambiguous interval (Doppler aliasing)
2. RangeRateLimitsAccepts/rejects based on the folded value

A target with true radial speed -120 m/s and MaxUnambiguousRadialSpeed=50 folds to -20 m/s. RangeRateLimits=[-25, 25] accepts it; [-10, 10] rejects it.

Physical Interpretation
  • Range: The radar illuminates targets out to RangeLimits (physical detection envelope). Ambiguity arises because pulse repetition makes the measurement ambiguous — the radar detects the target but reports a folded range.

  • Range rate: Doppler aliasing is inherent to the waveform — the radar never observes true speed, only the aliased value. Gating naturally applies to what the radar measures.

Configuration Guidance
  • RangeLimits must encompass all true target ranges you want detected, regardless of MaxUnambiguousRange. Setting RangeLimits=[0, MaxUnambiguousRange] defeats the purpose of range ambiguity modeling.

  • RangeRateLimits operates on folded speed. To reject targets by true speed, filter detections post-hoc (not possible from measurement alone without resolving ambiguity).

  • PRF-derived values: MaxUnambiguousRange = c/(2*PRF), MaxUnambiguousRadialSpeed = lambda*PRF/4.

  • Ghost targets at folded ranges are a real modeling effect — a target at 50 km reports at 20 km and is indistinguishable from a true 20 km target in the detection output.

Datasheet Ingestion

When a user provides a radar datasheet:

  1. Extract all stated parameters and map to the groups above

  2. Identify which groups are fully constrained, partially constrained, or unconstrained

  3. For partially constrained groups, compute the missing parameter using the API in the table

  4. For unconstrained groups, propose reasonable defaults with justification

  5. Flag any conflicts (e.g., stated range exceeds what the hardware can achieve)

  6. Determine integration type:

    • If CPI or number of coherent pulses stated: coherent. Gci = -pow2db(Ncoh)

    • If "N pulses non-coherent" or "post-detection integration": pass N to detectability

    • If both: full decomposition (Gci from Ncoh, Nnoncoh passed to detectability)

  7. Compute achievable range via the full bridge procedure above (detectability decomposition → radareqrng)

  8. Compare to any stated range requirement — this is the self-consistency check

  9. If stated range > computed range: the hardware cannot achieve the requirement. Quantify the gap and suggest which parameter to trade (power, gain, integration time, or relaxed Pd)


Copyright 2026 The MathWorks, Inc.


Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
MathWorks
Publisher
MathWorks (Official)
Source
matlab/matlab-agentic-toolkit · skills-catalog/radar/matlab-simulate-radar-detections · commit 2a7f215
Licence
BSD 2-Clause License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE.md)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by MathWorks or MathWorks.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download matlab-simulate-radar-detections.zip