Skip to main content

Circulax

logo

A differentiable circuit simulator built on JAX. Define netlists, run transient / DC / AC / harmonic-balance analysis, and differentiate through the solver for gradient-based optimization and inverse design. Circulax aims to be flexible multi-disciplined circuit simulator offering a similar interface to the linear s-parameter solver SAX.

Read the Documentation here

Installation

pip install circulax

Quickstart

Simulate an underdamped LCR circuit in the time domain:

LCR transient animation

import jax, jax.numpy as jnp
from circulax import compile_circuit
from circulax.components.electronic import Capacitor, Inductor, Resistor, VoltageSource

jax.config.update("jax_enable_x64", True)

net_dict = {
    "instances": {
        "GND": {"component": "ground"},
        "V1":  {"component": "source_voltage", "settings": {"V": 1.0, "delay": 0.25e-9}},
        "R1":  {"component": "resistor",        "settings": {"R": 10.0}},
        "C1":  {"component": "capacitor",       "settings": {"C": 1e-11}},
        "L1":  {"component": "inductor",        "settings": {"L": 5e-9}},
    },
    "connections": {
        "GND,p1": ("V1,p2", "C1,p2"),
        "V1,p1": "R1,p1",  "R1,p2": "L1,p1",  "L1,p2": "C1,p1",
    },
}

models = {
    "resistor": Resistor, "capacitor": Capacitor,
    "inductor": Inductor, "source_voltage": VoltageSource, "ground": lambda: 0,
}

circuit = compile_circuit(net_dict, models)
y_op    = circuit.dc()

sol = circuit.transient(
    t0=0.0, t1=3e-9, dt0=3e-12, y0=y_op,
    saveat=jnp.linspace(0, 3e-9, 500),
    max_steps=100_000,
)

v_cap = circuit.port(sol.ys, "C1,p1")  # capacitor voltage over time

Common analyses use the same compiled object:

op = circuit.dc()
op_sweep = circuit.dc(params={"R1.R": 20.0, "wavelength_nm": 1310.0})
S = circuit.ac(ports=["C1,p1"], freqs=jnp.logspace(6, 10, 101), y_dc=op)
y_time, y_freq = circuit.hb(freq=1e6, harmonics=5, y0=op)
v_out = circuit.port(op, "C1,p1")

Parameter keys like "R1.R" update one instance. Keys without a dot, such as "wavelength_nm", are broadcast to every component that declares the parameter.

Defining Components

Components are plain Python functions — no boilerplate, no subclassing:

from circulax.components.base_component import component, Signals, States

@component(ports=("p1", "p2"))
def Resistor(signals: Signals, s: States, R: float = 1e3):
    i = (signals.p1 - signals.p2) / R
    return {"p1": i, "p2": -i}, {}          # (currents, charges)

@component(ports=("p1", "p2"))
def Capacitor(signals: Signals, s: States, C: float = 1e-12):
    q = C * (signals.p1 - signals.p2)
    return {}, {"p1": q, "p2": -q}          # dq/dt becomes current automatically

Non-linear opto-electronic components are just as simple — the Jacobian is computed automatically via Automatic Differentiation:

@component(ports=("optical_in", "anode", "cathode"))
def Photodetector(signals: Signals, s: States,
                  responsivity: float = 0.8, dark_current: float = 1e-9):
    optical_power = jnp.abs(signals.optical_in) ** 2           # non-linear
    i_photo = responsivity * optical_power + dark_current
    i_reflect = -0.01 * signals.optical_in                     # small back-reflection
    return {"optical_in": i_reflect, "anode": i_photo, "cathode": -i_photo}, {}

Existing SAX models plug in directly — reuse your photonic PDK as-is:

import sax
from circulax.s_transforms import sax_component

Straight = sax_component(sax.models.straight)   # that's it — ready to simulate

Features

  • Transient — implicit ODE stepping via Diffrax; handles stiff circuits.
  • DC operating point — Newton-Raphson root-finding via Optimistix.
  • Harmonic Balance — periodic steady state directly in the frequency domain.
  • AC sweep — linearise at DC op-point, sweep frequency, return S-parameters.
  • OSDI compact models — load OpenVAF-compiled Verilog-A models through bosdi.
  • Automatic differentiation — differentiate through the solver for gradient-based inverse design.
  • Hardware-agnostic — CPU, GPU, or TPU with no code changes.
  • Mixed-domain — electronic and photonic circuits in a single netlist.

Comparison to SPICE

Circulax is a SPICE-like simulator but built with modern tooling so users can easily create their own models in a language they know.

SPICE circulax
Model definition Verilog-A / hardcoded C++ Python functions
Derivatives Hardcoded or compiler-generated Automatic differentiation
Solver Fixed/heuristic stepping Adaptive ODE (Diffrax)
Hardware CPU-only CPU / GPU / TPU

Inverse Design via Back-propagation

Because the entire solver is written in JAX, gradients flow end-to-end from a loss function back through the simulation and into component parameters. Use jax.grad and standard optimizers to automatically tune circuit designs — the cost is one forward + one backward pass regardless of parameter count.

See the Inverse Design guide for a comparison with finite differences and worked examples.


Copyright © 2026 Chris Daunt — Apache-2.0

Metadata

Release files for circulax 0.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for circulax 0.2.2
File Size Uploaded
circulax-0.2.2.tar.gz 3.5 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for circulax 0.2.2
File Interpreter ABI Platform
circulax-0.2.2-py3-none-any.whl Python 3 none any Details

Total release size: 3.7 MB

Release files / circulax-0.2.2.tar.gz

Download URL circulax-0.2.2.tar.gz
Size 3.5 MB
Tags Source
SHA-256 checksum
How to use checksums
de5bd636cb00f0d77ec8439a87633004d6eb0ab7f5c26c3e9db0b1decb97d110
BLAKE2b-256 checksum
How to use checksums
d500a9ceef0dd19a62e696d81c32c2ca3000a0a8824e2b227ed7b5aebb049a16
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Release files / circulax-0.2.2-py3-none-any.whl

Download URL circulax-0.2.2-py3-none-any.whl
Size 185.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
484781e397784331babb2b4de22421fef429828eb25eaa90ed271435bb6eeef8
BLAKE2b-256 checksum
How to use checksums
167af2de0abc131c14b46767b98b561acfba6e1a1c6a65696e2190614cd3ce47
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.4

2 release files

0.2.3

2 release files

This release

0.2.2 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page