Targets
PointTargets, StructureTargets and Aspect, the records that say where the scatterers are, how strongly they scatter, and how they move.
A Scene's meshes reflect and occlude, but they add no scatterers. Every simulation call names its scatterers with one targets record. See Scenes and targets.
from witwin.radar import Aspect, PointTargets, StructureTargetsEvery record takes exactly one of rcs and amplitude. They are two forms of the same strength, related by amplitude = sqrt(4 · pi · rcs) / wavelength.
PointTargets#
class PointTargets(positions, rcs=None, amplitude=None, phase=0.0, trajectory=None, ids=None, aspect=None)Point scatterers at world positions you give.
World positions, m. A tensor is passed through unchanged, so a requires_grad tensor or a forward-mode dual keeps its graph. A tensor must be on Radar.device.
NoneRadar cross section, m², shared by every target. A 0-dim tensor can carry a gradient.
NoneDimensionless strength sqrt(4 · pi · rcs) / wavelength, instead of rcs.
0.0Scattering phase, rad.
Nonetrajectory(t) returns the positions of the same ordered points at time t, s. None means the targets do not move. Rotation and articulation must move the points themselves.
NoneStable world IDs, one per target. None allocates them.
NoneAspect-dependent scattering. None scatters isotropically.
Raises
ValueError: both or neither ofrcsandamplitude; a strength vector with more than zero dimensions and noaspect.TypeError:trajectoryis not callable;aspectis not anAspect.ValueErrorat simulation: a positions tensor on a different device than the radar; a vectorrcs, even with anaspect.
| Property | Returns |
|---|---|
count | Number of targets, int. |
import torch
from witwin.radar import PointTargets
start = torch.tensor([[0.0, 0.0, -4.0]], device=radar.device)
def walk(t):
return start + torch.tensor([[0.0, 0.0, 1.5 * t]], device=radar.device) # 1.5 m/s toward the radar
targets = PointTargets(positions=start, rcs=1.0, trajectory=walk)StructureTargets#
class StructureTargets(rcs=None, amplitude=None, structure_ids=None, phase=0.0, ids=None)One scatterer at the world anchor Core publishes for each selected structure. The anchor exists only for a structure with rigid motion, such as a LinearTrajectory in a DynamicScene.
NoneRadar cross section, m², shared by every selected structure.
NoneDimensionless strength instead of rcs.
NoneStructures to place a scatterer on. None takes every structure in the snapshot. Order is by ascending structure ID.
0.0Scattering phase, rad.
NoneStable world IDs, one per selected structure. None allocates them.
Raises ValueError for both or neither of rcs and amplitude. NotImplementedError at simulation for a structure without rigid motion; Radar does not sample scatterers from a mesh.
targets = StructureTargets(rcs=1.0, structure_ids=(7,))
result = radar.simulate(dynamic_scene, targets, times=(0.0,), reflections=0)Aspect#
class Aspect(axis, exponent, coherent_interval, phase_rate=0.0)Aspect-dependent scattering for a target that is not a sphere. The response of a round trip is
amplitude * max(-dot(dir_in, axis), 0)^n * max(dot(dir_out, axis), 0)^nso axis is the direction of strongest return and exponent sets how fast the return falls away from it. With an Aspect, PointTargets.amplitude may be a vector with one value per target. rcs must still be a scalar: a vector rcs raises ValueError at simulation.
One unit vector per target, world frame. Not normalized for you.
Lobe sharpness n, at least 1. Larger is narrower.
How long one aspect realization stays coherent, s. Must be positive.
0.0Aspect phase drift, rad/s.
Raises ValueError for exponent < 1, a non-positive coherent_interval, or an axis whose shape is not (S, 3) for S targets.
axis = torch.tensor([[0.0, 0.0, 1.0], [0.0, 0.0, 1.0]], device=radar.device)
rcs = torch.tensor([1.0, 0.5], device=radar.device)
targets = PointTargets(
positions=[(-0.5, 0.0, -3.0), (0.5, 0.0, -3.0)],
amplitude=torch.sqrt(4 * torch.pi * rcs) / radar.wavelength, # one strength per target
aspect=Aspect(axis=axis, exponent=2.0, coherent_interval=0.1),
)