Results and paths
The Result, Frame and Paths records returned by Radar's verbs, with every field, the processing shortcuts on Frame, and the ProcessingAxes metadata.
simulate and echo return a Result; stream yields one Result per frame; trace returns Paths. All three are frozen dataclasses that hold data only.
from witwin.radar import Frame, Paths, ResultResult#
What one simulate or echo call produced. You do not construct it yourself.
| Field | Type | Meaning |
|---|---|---|
cube | torch.Tensor | Complex cube [frame, tx, rx, slow, fast]. Carries the autograd graph when grad was set. |
times_s | tuple[float, ...] | Frame start times, s. |
kind | str | Waveform kind: "fmcw", "ofdm" or "pulsed". |
axis_names | tuple[str, ...] | Names of the cube axes, for example ('frame', 'tx', 'rx', 'chirp', 'range_bin'). |
axes | ProcessingAxes | Physical axes and conventions of the cube. |
phasor | str | Phase convention of the cube. |
time_dependence | str | Time convention, exp(+j·2π·f·t). |
reference_frequency_hz | float | Carrier the paths were evaluated at, Hz. |
output_domain | str | "spectrum" or "beat" for FMCW, "cfr" (channel frequency response) for OFDM, "time" for pulsed. |
epochs | tuple[int, ...] | Compile epoch of each frame. A new epoch means the Scene was recompiled. |
rediscovery_reasons | tuple[str or None, ...] | Why the topology was rediscovered at each frame, or None. |
compile_count | int | Number of Scene compiles in the run. |
discovery_count | int | Number of path discoveries in the run. |
sample_times_s | tuple | Observation times used in each frame. |
path_set_complete | bool | True when no path appearance can have been missed. |
motion_sampling_exhaustive | bool | True when no observation was interpolated. |
motion_sampling | str | The motion mode that ran, for example "chirp" or "adc". Motion.auto() reports the mode it chose. |
adaptive_diagnostics | tuple[dict, ...] | Per-frame adaptive statistics; empty without Motion.adaptive(). |
last_snapshot | object | Core snapshot of the last frame. |
last_compiled_scene | object | Channel compiled Scene of the last frame. |
last_propagation | object | Propagation legs of the last frame. |
last_radar_paths | RadarPathBatch | Composed round trips of the last frame's final observation. |
last_radar_paths has, among others, path_count, sensor_pair_count, total_delay_s (round-trip delay per row, s) and complex_transfer_ref (transfer coefficient per row at the carrier). The last_* fields alias that frame's device tensors, so holding a Result holds that memory.
An adaptive diagnostics dictionary has the keys evaluations, topology_refinements, accepted_intervals, max_tested_phase_error_rad, max_tested_relative_amplitude_error, max_interval_s, exhaustive, topology_proved_complete, interpolation_nodes, observation_count and synthesis_batches.
Result.frame_count#
int, the number of frames in cube.
Result.frame#
Result.frame(index=0) -> FrameOne frame with the metadata processing needs. A view: the cube is indexed, not copied.
0Frame index within this result.
Returns Frame.
Result.frame_synthesis#
Result.frame_synthesis(frame_index=0) -> SynthesisResultOne frame's cube and its conventions as a SynthesisResult, without running synthesis again. See Synthesis.
Frame#
One frame of a Result. Its methods call witwin.radar.processing with the frame's own cube and axes, so a cube cannot be paired with the wrong array.
| Field | Type | Meaning |
|---|---|---|
cube | torch.Tensor | Complex [tx, rx, slow, fast]. |
axes | ProcessingAxes | Physical axes of this frame. |
time_s | float | Frame start time, s. |
index | int | Index within the Result. 0 for every frame from stream. |
synthesis | SynthesisResult | The frame's synthesis record. |
Frame.processing_cube#
Frame.processing_cube() -> ProcessingCubeThe cube and its axes as the typed record every processing function takes.
Frame.range_profile#
Frame.range_profile(*, window=None, remove_dc=False) -> RangeProfileRange profile of every TX-RX pair and slow-time sample.
NoneFast-time window: "rectangular", "hann", "hamming" or "blackman". None is rectangular. An FMCW "spectrum" cube is already range-transformed and refuses a window; use Fmcw(output="beat") to taper.
FalseSubtract the fast-time mean before the transform.
Frame.range_doppler#
Frame.range_doppler(*, window='hann', range_window=None, remove_dc=False) -> RangeDopplerMapRange-Doppler map, [tx, rx, doppler, range], with a positive Doppler bin for a closing target.
'hann'Slow-time window.
NoneFast-time window, passed to the range stage.
FalseSubtract the fast-time mean before the range transform.
Frame.array#
Frame.array() -> ArrayGeometryThe virtual-array geometry the frame's axes describe. See Angle estimation.
Frame.points#
Frame.points(*, pfa=0.0001, guard_cells=(2, 4), training_cells=(4, 8), route='phase_comparison',
fft_size=64, max_points=None, window='hann') -> PointCloudRange-Doppler map, coherent sum over sensor pairs, CA-CFAR and a point cloud, in one call.
0.0001Design false-alarm probability of the CA-CFAR threshold.
(2, 4)Guard cells on each side, (doppler, range).
(4, 8)Training cells on each side beyond the guard cells, (doppler, range).
'phase_comparison'Angle estimator: "phase_comparison" or "fft2".
64Angle FFT size.
NoneKeep only the strongest cells. None keeps every detection.
'hann'Slow-time window of the range-Doppler stage.
Returns PointCloud. See Detection.
frame = result.frame(0)
rd = frame.range_doppler()
cloud = frame.points(max_points=64)
print(frame.axes.range_bin_m, len(cloud))ProcessingAxes#
The physical axes and conventions of a cube, in witwin.radar.processing. Frame.axes and Result.axes hold one. Every processing stage reads its axes from here.
| Field | Meaning |
|---|---|
waveform, output_domain | Waveform kind and output domain. |
fast_time_name, slow_time_name | Axis names, for example "range_bin" and "chirp". |
slow_time_period_s | Slow-time sample period, s. For TDM-MIMO FMCW, the slot period chirp_period · num_tx. |
range_bin_count, doppler_bin_count | Axis lengths. |
range_bin_m, range_origin_m | Range bin size and first bin, m. |
max_unambiguous_range_m | Range at which the axis wraps, m. |
velocity_bin_mps, max_unambiguous_speed_mps | Velocity bin size and aliasing bound, m/s. |
wavelength_m, reference_frequency_hz | Carrier wavelength, m, and frequency, Hz. |
phasor, doppler_sign | Phase convention and the sign used to make closing velocity positive. |
num_tx, num_rx, element_spacing_m | Array size and grid spacing, m. |
tx_loc_half_wavelength, rx_loc_half_wavelength | Element offsets in half wavelengths. |
range_m | [R] float64 range axis, m. |
velocity_mps | [D] float64 velocity axis, m/s, closing positive. |
range_oversample | Range oversampling factor. |
axes.units returns a dictionary from each scalar name to its SI unit, and axes.sensor_pair_count is num_tx · num_rx.
Paths#
The round trips one trace call composed, before any waveform or receiver stage. Pass it to Radar.echo.
| Field or property | Meaning |
|---|---|
kind | How often the world was sampled: "static", "chirp", "adc" or "adaptive". |
carrier, waveform | Carrier and waveform the schedule was built from. |
times, sample_times | Frame times and observation times, s. |
los, reflections, grad, motion | The trace request. |
epochs, rediscovery_reasons, compile_count, discovery_count | As on Result. |
path_set_complete, motion_sampling_exhaustive, adaptive_diagnostics | As on Result. |
last_snapshot, last_compiled_scene, last_propagation, last_radar_paths | As on Result. |
frame_count | Frames covered. |
observation_count | Observation instants evaluated, summed over frames. For adaptive traces, the schedule size, not the probe count. |
row_count | Composed rows kept, summed over every observation. |
Paths.frame#
Paths.frame(index) -> PathsOne frame's rows as a Paths of its own, which can be echoed.
Paths.rows#
Paths.rows(frame=0, observation=-1) -> RadarPathBatchOne observation's composed rows. An adaptive frame keeps only its closing observation; asking for another raises.
paths = radar.trace(scene, targets, times=(0.0, 0.05), reflections=1)
rows = paths.rows(frame=0)
print(rows.path_count, rows.total_delay_s[:4], rows.complex_transfer_ref[:4])
single = radar.echo(paths.frame(1))