Solvers

deterministic, montecarlo, and path solver API reference

Overview#

WiTwin Channel has three solver packages, all following the same pattern:

result = wc.<solver>.solve(scene=scene, transmitter="tx", receiver="rm", config=config)

All three are lazy-loaded on first access — import witwin.channel as wc and use wc.deterministic, wc.montecarlo, or wc.path directly.


Deterministic solver#

Fast, repeatable radiomap over a ReceiverGrid. Use this as your default solver.

result = wc.deterministic.solve(
    scene=scene,
    transmitter="tx",
    receiver="rm",
    config=wc.deterministic.Config(
        num_samples=256,
        max_bounces=2,
        max_diffraction_order=1,
        edge_policy=wc.EdgePolicy(edge_selection_mode="all_edges"),
    ),
)

wc.deterministic.Config#

ParameterDefaultDescription
num_samples10000Number of rays
max_bounces2Maximum reflection bounces. Must be >= 0
max_diffraction_order1Maximum diffraction order. Must be >= 0
metric"path_gain"Output metric. One of "path_gain", "rss", "sinr"
quadrature_mode"center"Cell quadrature mode. One of "center", "stratified_fixed_n"
samples_per_cellNoneSamples per cell for "stratified_fixed_n" mode
shadow_boundary_correctionFalseEnable shadow boundary correction
synthetic_arrayTrueUse synthetic antenna array
edge_policyNoneEdge selection policy
tuningNoneAdvanced controls via wc.deterministic.Tuning

wc.deterministic.solve() result#

Returns a RadioMapResult with:

FieldDescription
path_gainSignal path gain at every grid point
rssReceived signal strength
sinrSignal-to-interference-plus-noise ratio
componentsPer-component breakdown ("los", "reflection", "diffraction")
coordsGrid coordinates via RadioMapCoordinates

Field solver#

The deterministic package also exposes solve_field() for computing the full EM field on a plane. See Field Simulation.


Monte Carlo solver#

Sampling-based radiomap using transmitter-driven ray integration. Use when you need stochastic integration over complex scenes.

result = wc.montecarlo.solve(
    scene=scene,
    transmitter="tx",
    receiver="rm",
    config=wc.montecarlo.Config(
        num_samples=128,
        max_bounces=1,
        max_diffraction_order=1,
        integrator_options=wc.montecarlo.IntegratorOptions(
            integrator="basic",
            samples_per_tx=4096,
            seed=7,
        ),
    ),
)

wc.montecarlo.Config#

ParameterDefaultDescription
num_samples10000Number of rays
max_bounces2Maximum reflection bounces. Must be >= 0
max_diffraction_order1Maximum diffraction order. Range [0, 3]. "basic" integrator supports [0, 1] only
synthetic_arrayTrueUse synthetic antenna array
edge_policyNoneEdge selection policy
integrator_optionsNoneIntegrator controls via IntegratorOptions
filteringNoneDifferentiable power filtering via FilterConfig
tuningNoneAdvanced controls via wc.montecarlo.Tuning

wc.montecarlo.IntegratorOptions#

ParameterDefaultDescription
integrator"basic"Integrator type. One of "basic", "bdpt"
samples_per_tx65536Samples per transmitter
seed0Random seed
accumulation_backend"auto"Backend. One of "auto", "native_monte_carlo", "rayd_reflection_accumulation"
rr_depthNoneRussian roulette start depth
rr_probNoneRussian roulette survival probability. Range (0, 1]
stop_thresholdNoneRay contribution stop threshold
adNoneForce autodiff mode on or off

wc.montecarlo.FilterConfig#

Optional differentiable power-domain filtering for gradient smoothing:

wc.montecarlo.FilterConfig(
    reflection=wc.montecarlo.ComponentFilterConfig(method="gaussian", radius=1, sigma=1.0),
    diffraction=wc.montecarlo.ComponentFilterConfig(method="bilateral", radius=2, sigma=1.0),
)

wc.montecarlo.ComponentFilterConfig#

ParameterDefaultDescription
method"gaussian"Filter method. One of "gaussian", "bilateral"
radius1Filter radius in cells. Must be >= 0
sigma1.0Spatial sigma. Must be > 0
range_sigmaNoneRange sigma for bilateral filter. Defaults to sigma
blend1.0Blend weight. Range [0, 1]

Result#

Returns a RadioMapResult with the same fields as the deterministic solver.


Path solver#

Discrete per-receiver path export. Use when you need CIR, CFR, or individual path data.

path_result = wc.path.solve(
    scene=scene,
    transmitter="tx",
    receiver=["rx0", "rx1"],
    config=wc.path.Config(
        num_samples=256,
        max_bounces=1,
        max_diffraction_order=0,
        max_num_paths=8,
        return_geometry=True,
        edge_policy=wc.EdgePolicy(edge_selection_mode="all_edges"),
    ),
)

Note

The path solver requires named Receiver endpoints, not ReceiverGrid. Pass receiver names as a string or list of strings.

wc.path.Config#

ParameterDefaultDescription
num_samples10000Number of rays
max_bounces2Maximum reflection bounces. Must be >= 0
max_diffraction_order1Maximum diffraction order. Must be >= 0
max_num_pathsNoneMaximum paths to return per receiver. Must be > 0 when set
return_geometryFalseReturn per-path vertex, normal, and object data
synthetic_arrayTrueUse synthetic antenna array
edge_policyNoneEdge selection policy
tuningNoneAdvanced controls via wc.path.Tuning

PathResult methods#

MethodDescription
.cir(normalize_delays=True)Returns (coefficients, delays) as torch tensors
.cfr(frequencies, normalize_delays=True)Channel frequency response over subcarrier frequencies
.taps(bandwidth, num_taps, normalize_delays=True)Discrete channel taps at a given bandwidth
.filter_by_type(*interaction_types)Filter paths by InteractionType

PathResult fields#

FieldDescription
aComplex path coefficients
tauPath delays
theta_t, phi_tAngle of departure (elevation, azimuth)
theta_r, phi_rAngle of arrival (elevation, azimuth)
validBoolean mask for valid paths
typesInteraction types per depth slot
num_pathsNumber of valid paths per receiver
verticesPath vertex positions (if return_geometry=True)
normalsSurface normals at interaction points (if return_geometry=True)

InteractionType#

wc.path.InteractionType.REFLECTION
wc.path.InteractionType.DIFFRACTION
wc.path.InteractionType.TRANSMISSION
wc.path.InteractionType.SCATTERING

Next Steps#