Skip to content

[FEATURE] Implement transition_matrices #431

@rwydaegh

Description

@rwydaegh

Terms

  • Checked the existing issues to see if my suggestion has not already been suggested;

Description

transition_matrices() in differt/em/_utils.py:307 has a skeleton but raises NotImplementedError. It accepts vertices, objects, interaction_types, object_normals, computes ray direction vectors, makes a zero Jones matrix, then hits mat_r = mat # TODO: fixme and gives up.

This is the function that should compute the 2x2 Jones transfer matrix for a whole path, accumulating all reflections and diffractions. Without it, multi-bounce polarization tracking doesn't work, and interaction_types on Paths goes unused.

@jax.jit
def transition_matrices(
    vertices: Float[ArrayLike, "*batch path_length 3"],
    objects: Int[ArrayLike, "*batch path_length"],
    interaction_types: Int[ArrayLike, "*batch path_length-2"],
    object_normals: Float[ArrayLike, "num_objects 3"],
    *,
    n_r: Inexact[ArrayLike, " num_objects"] | None = None,
    wavenumber: Float[ArrayLike, ""] | None = None,
    wedge_angles: Float[ArrayLike, " num_objects"] | None = None,
) -> Complex[Array, "*batch 2 2"]:
    """2x2 Jones transfer matrix per path.
    T = R_N @ M_N @ ... @ R_1 @ M_1
    """

Implementation would be jax.lax.scan over interaction points, with jax.lax.switch on interaction_types to pick reflection vs diffraction coefficients. The building blocks are there: sp_directions, sp_rotation_matrix, fresnel_coefficients. Getting the basis rotation chain right across N interactions is the hard part. sp_rotation_matrix does one rotation; chaining them needs careful bookkeeping of which frame you're in.

I think this makes sense in two phases. First: reflection only, using existing Fresnel + sp_rotation infrastructure. Then add diffraction once #429 lands.

The companion compute_received_fields issue can start without this (just apply Fresnel directly like deepmimo.py does), but eventually this becomes the cleaner way to do it, and it's the right fix for the multi-bounce polarization errors that tripped up #355.

For validation: single reflection against the worked example in reflection_coefficients docstring, identity matrix for LOS paths, and reciprocity check (T for TX->RX should equal transpose of T for RX->TX).

#427 (compute_received_fields) can work without this initially, but should eventually use it internally. The diffraction branch needs both #429 (UTD coefficients, for D_s, D_h) and #428 (edge detection, for wedge_angles). #355 got stuck on multi-bounce polarization; this is what's actually needed to fix that.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestnice-to-haveA nice to have feature (or else)

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions