Skip to content

Additive Backend

The additive backend can be used to calculate path lengths, group delays, and other additive quantities. Unlike the default multiplicative backend (which multiplies S-parameters along paths), the additive backend sums values. This is useful for computing optical path lengths, propagation delays, or any linear quantity that accumulates along the signal path.

from functools import partial

import jax.numpy as jnp
from sax.models import straight
import matplotlib.pyplot as plt

import sax

How the Additive Backend Works

In standard S-parameter simulations, we multiply transmission coefficients along signal paths. For example, if light passes through two waveguides with transmissions \(T_1\) and \(T_2\), the total transmission is \(T_1 \times T_2\).

With the additive backend, values are summed instead of multiplied. This is useful for quantities like: - Path length: Total physical length = \(L_1 + L_2\) - Group delay: Total delay = \(\tau_1 + \tau_2\) - Phase (unwrapped): Total phase = \(\phi_1 + \phi_2\) - Loss (in dB): Total loss = \(\text{Loss}_1 + \text{Loss}_2\)

The additive backend uses the same netlist structure, but interprets the "S-parameter" values as additive quantities.

Path Length Models

Let's define models that return path lengths instead of transmission coefficients. The coupler has a physical length that light traverses regardless of which port it exits from:

def coupler(length=50.0) -> sax.SDict:
    """Coupler model returning path lengths (in μm)."""
    sdict = {
        ("in0", "out0"): length,
        ("in0", "out1"): length,
    }
    return sax.reciprocal(sdict)


def waveguide(length=50.0) -> sax.SDict:
    """Coupler model returning path lengths (in μm)."""
    sdict = {
        ("in0", "out0"): length,
    }
    return sax.reciprocal(sdict)

def waveguide(length=100.0) -> sax.SDict: """Waveguide model returning path lengths (in μm).""" sdict = { ("in0", "out0"): length, } return sax.reciprocal(sdict)

MZI with Additive Backend

Let's create an MZI (Mach-Zehnder Interferometer) with different arm lengths and use the additive backend to calculate the total path length through each arm:

          ┌─────────────────────────┐
     ┌─────┤    top (500 μm)     ├─────┐
     │    └─────────────────────────┘     │
in ──┤ lft                        rgt ├── out
     │    ┌─────────────────────────┐     │
     └─────┤    btm (100 μm)     ├─────┘
          └─────────────────────────┘
mzi, _ = sax.circuit(
    netlist={
        "instances": {
            "lft": coupler,
            "top": partial(waveguide, length=500),
            "btm": partial(waveguide, length=100),
            "rgt": coupler,
        },
        "connections": {
            "lft,out0": "btm,in0",
            "btm,out0": "rgt,out0",
            "lft,out1": "top,in0",
            "top,out0": "rgt,out1",
        },
        "ports": {
            "in0": "lft,in0",
            "out0": "rgt,in0",
        },
    },
    backend="additive",
)

result = mzi()
result
{('in0', 'in0'): [Array([0.], dtype=float64)],
 ('in0', 'out0'): [Array([200.], dtype=float64), Array([600.], dtype=float64)],
 ('out0', 'in0'): [Array([200.], dtype=float64), Array([600.], dtype=float64)],
 ('out0', 'out0'): [Array([0.], dtype=float64)]}

Interpreting the Results

The additive backend returns the total path length for each input-output port combination. Let's analyze the results:

path_lengths = result["in0", "out0"]

print(f"first path: {path_lengths[0][0]:.1f} μm")
print(f"second path: {path_lengths[1][0]:.1f} μm")

delta_L = path_lengths[1][0] - path_lengths[0][0]
print(f"\nPath length difference (ΔL): {delta_L:.1f} μm")
first path: 200.0 μm
second path: 600.0 μm

Path length difference (ΔL): 400.0 μm

When to Use the Additive Backend

The additive backend is useful when you need to:

  1. Calculate optical path lengths - Important for interferometer design, determining FSR (Free Spectral Range)
  2. Compute group delays - Essential for high-speed communication systems and pulse propagation
  3. Sum losses in dB - Convenient for loss budgeting when models return loss in dB
  4. Analyze phase accumulation - When you want to track unwrapped phase

The additive backend uses the same circuit analysis infrastructure as the standard backend, so it handles complex circuits with multiple paths correctly. When multiple paths exist between ports, each path's contribution is computed separately.