Simulation#

Point targets, propagation paths, scene sampling, and optional mesh ray tracing live in pyradar.sim. ADC synthesis uses the same waveform, array, and MIMO timing contracts as the processing pipeline.

Model-aware radar simulation.

The core point-target simulator depends only on NumPy. Mesh ray tracing is loaded lazily and requires the simulation optional dependency.

class pyradar.sim.PointTarget(position, velocity=<factory>, rcs=1.0, phase=0.0)[source]#

Bases: object

Ideal isotropic point target in the radar FLU frame.

Parameters:
position:

Target position at time zero as [x, y, z] in meters.

velocity:

Constant Cartesian velocity in meters per second.

rcs:

Monostatic radar cross section in square meters. Its square root is used as the complex field amplitude before optional propagation loss.

phase:

Additional reflection phase in radians.

Parameters:
  • position (NDArray[float64])

  • velocity (NDArray[float64])

  • rcs (float)

  • phase (float)

position: NDArray[float64]#
velocity: NDArray[float64]#
rcs: float#
phase: float#
position_at(time)[source]#

Return the FLU position at time seconds.

Parameters:

time (float)

Return type:

NDArray[float64]

property reflection: complex#

Complex field reflection coefficient before path loss.

class pyradar.sim.PropagationPath(pathLength, txId, rxId, pathRate=0.0, amplitude=1 + 0j)[source]#

Bases: object

One bistatic propagation path at the beginning of a frame.

pathRate is positive when the total TX-target-RX path length is increasing. Consequently, an approaching target produces positive Doppler frequency and has a negative path rate.

Parameters:
pathLength: float#
txId: int#
rxId: int#
pathRate: float#
amplitude: complex#
class pyradar.sim.RangeImage(ranges, azimuth, elevation, pointIndices, features=None)[source]#

Bases: object

Nearest-return angular projection of a point scene.

Parameters:
  • ranges (NDArray[float64])

  • azimuth (NDArray[float64])

  • elevation (NDArray[float64])

  • pointIndices (NDArray[int64])

  • features (NDArray | None)

ranges: NDArray[float64]#
azimuth: NDArray[float64]#
elevation: NDArray[float64]#
pointIndices: NDArray[int64]#
features: NDArray | None#
class pyradar.sim.RayPath(points, hitReceiver, gain=1 + 0j)[source]#

Bases: object

Piecewise-linear SBR path.

Parameters:
  • points (NDArray[float64])

  • hitReceiver (bool)

  • gain (complex)

points: NDArray[float64]#
hitReceiver: bool#
gain: complex#
property length: float#
to_propagation_path(*, txId, rxId, pathRate=0.0)[source]#

Convert a receiver-terminated ray into an ADC propagation path.

Parameters:
Return type:

PropagationPath

class pyradar.sim.RayTraceResult(origins, directions, hitMask, points, distances, triangleIndices)[source]#

Bases: object

First mesh intersection for each input ray.

Parameters:
  • origins (NDArray[float64])

  • directions (NDArray[float64])

  • hitMask (NDArray[bool])

  • points (NDArray[float64])

  • distances (NDArray[float64])

  • triangleIndices (NDArray[int64])

origins: NDArray[float64]#
directions: NDArray[float64]#
hitMask: NDArray[bool]#
points: NDArray[float64]#
distances: NDArray[float64]#
triangleIndices: NDArray[int64]#
class pyradar.sim.TargetScene(targets)[source]#

Bases: object

An immutable collection of point targets.

Parameters:

targets (tuple[PointTarget, ...])

targets: tuple[PointTarget, ...]#
classmethod from_points(points, *, velocities=None, rcs=1.0, phase=0.0)[source]#

Build one point target per row of an (N, 3) point cloud.

Parameters:
  • points (ArrayLike)

  • velocities (ArrayLike | None)

  • rcs (ArrayLike | float)

  • phase (ArrayLike | float)

Return type:

TargetScene

classmethod coerce(targets)[source]#

Normalize a target or target sequence into a scene.

Parameters:

targets (PointTarget | Sequence[PointTarget] | TargetScene)

Return type:

TargetScene

class pyradar.sim.TrimeshRayTracer(mesh)[source]#

Bases: object

Lazy optional Trimesh first-hit and specular SBR backend.

Parameters:

mesh (Any)

classmethod from_file(path, *, process=False)[source]#

Load a mesh file without importing Trimesh at package import time.

Parameters:
Return type:

TrimeshRayTracer

trace(origins, directions)[source]#

Return the nearest mesh hit for every ray.

Parameters:
  • origins (ArrayLike)

  • directions (ArrayLike)

Return type:

RayTraceResult

shoot_and_bounce(origins, directions, *, receiverCenter, receiverRadius, maxBounces=3, reflectionCoefficient=1 + 0j, epsilon=1e-06)[source]#

Trace ideal specular rays until they hit a spherical receiver.

Parameters:
  • origins (ArrayLike)

  • directions (ArrayLike)

  • receiverCenter (ArrayLike)

  • receiverRadius (float)

  • maxBounces (int)

  • reflectionCoefficient (complex)

  • epsilon (float)

Return type:

tuple[RayPath, …]

pyradar.sim.fresnel_schlick(cosine, incidentIndex, transmittedIndex)[source]#

Return Schlick’s unpolarized power-reflection approximation.

Parameters:
Return type:

float

pyradar.sim.linear_trajectory(start, stop, *, numFrames)[source]#

Return (numFrames, 4, 4) FLU poses along a straight line.

Parameters:
  • start (ArrayLike)

  • stop (ArrayLike)

  • numFrames (int)

Return type:

NDArray[float64]

pyradar.sim.quantize_adc(frame, *, bitDepth=None, fullScale=None)[source]#

Quantize complex ADC components while retaining a complex array.

Parameters:
Return type:

ADCFrame

pyradar.sim.reflect(direction, normal)[source]#

Specularly reflect one direction around a surface normal.

Parameters:
  • direction (ArrayLike)

  • normal (ArrayLike)

Return type:

NDArray[float64]

pyradar.sim.refract(direction, normal, incidentIndex, transmittedIndex)[source]#

Apply Snell’s law, returning None for total internal reflection.

Parameters:
  • direction (ArrayLike)

  • normal (ArrayLike)

  • incidentIndex (float)

  • transmittedIndex (float)

Return type:

NDArray[float64] | None

pyradar.sim.render_range_image(points, *, radarPose=None, azimuthFov=(-1.5707963267948966, 1.5707963267948966), elevationFov=(-0.7853981633974483, 0.7853981633974483), angularResolution=(np.float64(0.017453292519943295), np.float64(0.017453292519943295)), maxRange=inf, features=None)[source]#

Project world points into a nearest-return azimuth/elevation image.

Parameters:
Return type:

RangeImage

pyradar.sim.sample_cone_directions(numRays, coneAngle, *, forward=(1.0, 0.0, 0.0), seed=None)[source]#

Uniformly sample unit directions within a cone in radians.

Parameters:
  • numRays (int)

  • coneAngle (float)

  • forward (ArrayLike)

  • seed (int | None)

Return type:

NDArray[float64]

pyradar.sim.sample_plane(*, width=1.0, height=1.0, numPoints=1000, center=(1.0, 0.0, 0.0), seed=None)[source]#

Sample a y-z plane facing the radar’s forward x direction.

Parameters:
  • width (float)

  • height (float)

  • numPoints (int)

  • center (ArrayLike)

  • seed (int | None)

Return type:

NDArray[float64]

pyradar.sim.sample_sphere(*, radius=1.0, numPoints=1000, center=(0.0, 0.0, 0.0), seed=None)[source]#

Uniformly sample points on a sphere surface.

Parameters:
  • radius (float)

  • numPoints (int)

  • center (ArrayLike)

  • seed (int | None)

Return type:

NDArray[float64]

pyradar.sim.simulate_adc(radar, targets, *, frameTime=0.0, propagationLoss=False, noisePower=0.0, seed=None, frameId=None)[source]#

Synthesize one raw ADC frame from ideal point targets.

Parameters:
Return type:

ADCFrame

pyradar.sim.simulate_paths(radar, paths, *, noisePower=0.0, seed=None, timestamp=None, frameId=None)[source]#

Synthesize canonical raw ADC from fixed linear propagation paths.

The phase convention matches pyradar.rsp.steering_vector(): an approaching path has negative pathRate and produces positive Doppler. MIMO coding and true emission times are taken from radar.mimo.

Parameters:
Return type:

ADCFrame

pyradar.sim.targets_to_paths(radar, targets, *, frameTime=0.0, propagationLoss=False)[source]#

Convert point targets into one bistatic path per TX/RX pair.

Parameters:
Return type:

tuple[PropagationPath, …]