--- name: matlab-simulate-radar-detections description: > 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. license: https://www.mathworks.com/content/dam/mathworks/license/pmrl/license.md metadata: author: MathWorks version: "1.0" --- # 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: | 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](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](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](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](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](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: | 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](references/radar-equation-tools.md#pd-vs-range-prediction-fluctuationmodel-dependent)). 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](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](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 - `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 | 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](references/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 | Mode | Key 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: ```matlab 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](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 | Symptom | Likely Cause | Diagnostic / Fix | |---------|-------------|-----------------| | No detections at all | `RangeLimits` too short | Check `radar.RangeLimits(2)` >= max target range | | No detections at all | Sensor `UpdateRate` = 1 Hz (default) | Beam scanning too slowly — set `UpdateRate` explicitly | | No detections at all (UpdateRate is set) | Scenario `UpdateRate` < sensor `UpdateRate` | FoV dwell aliasing — only sampled positions produce detections. Set scenario `UpdateRate` = sensor `UpdateRate`. | | No detections at all | Target outside beam FoV | Use `coverageConfig(radar)` to get current beam direction; compare to target bearing | | Detections only on some scans | Target near beam step boundary | Normal 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 detections | Self-detection (radar platform) | Filter: ignore detections where `TargetIndex == radar platform ID` (usually 1) | | Pd much lower than configured | Target beyond `ReferenceRange` | SNR drops as 40·log10(R) — expected; Pd is specified AT reference range only | | Pd higher than expected | Target RCS > `ReferenceRCS` | Higher RCS increases SNR — check `rcsSignature` on target platform | | Empirical Pd > 1.0 | Dividing detections by scans, not illuminations | Mechanical 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 truth | Plotting raw `.Measurement` against scenario-frame truth | **Must 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-limited | Targets beyond radar horizon | Use `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 fails | Hardware-derived Rmax ≠ configured ReferenceRange | Recheck `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: ```matlab % 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): ```matlab 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](references/coordinates-and-transforms.md#verification-spot-check-detections-against-truth) 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:** ```matlab origFoV = radar.FieldOfView; origScan = radar.ScanMode; release(radar); radar.FieldOfView = [360; 180]; radar.ScanMode = 'No scanning'; ``` 2. **Restart and re-run the scenario** (`restart(scenario)` + advance loop) 3. **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) 4. **Release and restore original config before continuing:** ```matlab 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](references/coordinates-and-transforms.md) 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 | |---------------------|-----------| | `HasElevation` | `ElevationResolution`, `ElevationBiasFraction`, `MaxElevationScanRate`, `MechanicalElevationLimits`, `ElectronicElevationLimits` | | `HasRangeRate` | `RangeRateResolution`, `RangeRateBiasFraction`, `RangeRateLimits`, `HasRangeRateAmbiguities` | | `HasRangeAmbiguities` | `MaxUnambiguousRange` | | `HasRangeRateAmbiguities` | `MaxUnambiguousRadialSpeed` | Properties gated by `ScanMode`: | ScanMode | Do 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`: | Format | Do NOT set | |--------|-----------| | `'Clustered detections'` or `'Detections'` | `FilterInitializationFcn`, `ConfirmationThreshold`, `DeletionThreshold`, `TrackCoordinates` | | `'Tracks'` | `DetectionCoordinates` | Properties gated by `DetectionMode`: | Mode | Do NOT set | |------|-----------| | `'ESM'` | `ReferenceRange`, `ReferenceRCS`, `DetectionProbability` | ## References Load only what the task requires — do not read all references for every prompt. | Reference | When to Read | |-----------|-------------| | [Detection Model](references/detection-model.md) | Configuring radar properties, debugging property names, understanding detection pathway | | [FoV & Scan](references/fov-and-scan.md) | Setting FieldOfView, scan mode config, UpdateRate/scan rate derivation | | [Coordinates & Transforms](references/coordinates-and-transforms.md) | Interpreting detections, converting frames, NED elevation/azimuth, plotting | | [Trajectories](references/trajectories.md) | Target motion, stationary platforms, scenario duration, body frame orientation | | [Terrain, Clutter & Atmosphere](references/terrain-clutter-atmosphere.md) | Adding surfaces, clutter generator, atmosphere models, occlusion | | [Radar Equation Tools](references/radar-equation-tools.md) | Bottom-up derivation, hardware-to-ReferenceRange bridge, Pd vs range | | [Visualization](references/visualization.md) | theaterPlot, coverage plots, radarmetricplot | | [Coupled Parameters](references/coupled-parameters.md) | Step 5: parameter-relationship table, datasheet ingestion | | [Interaction Flow](references/interaction-flow.md) | Full 9-step workflow with suggested phrasings | | [Requirements Sheet Template](references/requirements-sheet-template.md) | Step 9: three-section output artifact structure | ---- Copyright 2026 The MathWorks, Inc.