Substrate model¶
Shunt capacitance from metal traces to substrate ground.
For each polygon on metal layer m we model the capacitance to
the substrate’s bulk ground as a parallel-plate cap
with A the polygon’s footprint area, h the vertical distance
from the metal centreline to the bottom of the layer stack, and
ε_r the layer-stack-averaged relative permittivity. This is a
textbook approximation; the binary’s full Green’s-function path
captures lateral coupling that this stub ignores.
The fringe correction adds the standard 0.5·ε₀·(perimeter) term (Yuan & Trick 1982).
Mirrors the simpler half of coupled_microstrip_caps_hj
(asitic_kernel.c:0x0804df6c).
- reasitic.substrate.shunt.parallel_plate_cap_per_area(eps_r, h_um)[source]¶
C/A in F/μm² for a parallel-plate cap of dielectric
eps_rand thicknessh(μm).
- reasitic.substrate.shunt.shape_shunt_capacitance(shape, tech)[source]¶
Total shunt capacitance from
shapeto substrate ground, in F.For each polygon we model the path from its metal-layer centreline down to the substrate ground as a stack of series parallel-plate caps, one per dielectric layer between the metal and the ground:
\[\frac{1}{C_\text{path}} = \sum_k \frac{h_k}{\varepsilon_0 \varepsilon_{r,k} A}\]so the equivalent
ε_eff = h_total / Σ (h_k / ε_{r,k})only averages layers actually in the path to ground (rather than every substrate layer in the tech file as the previous version did). The fringe term keeps the same Yuan–Trick form onε_eff.Mirrors the simpler half of
coupled_microstrip_caps_hj(asitic_kernel.c:0x0804df6c).
Multi-layer substrate Green’s function via Sommerfeld integration.
For a planar inductor over a stratified substrate (silicon + oxide
+ optional metal back-plane) the proper electromagnetic coupling
goes via the Green’s function for an electric current source above
the stack. The textbook result is a Sommerfeld integral over the
radial wavenumber k_ρ:
where R(k_ρ) is the layered-stack reflection coefficient and
k_z = \sqrt{k_0^2 \varepsilon_r - k_\rho^2}.
The original ASITIC binary precomputes this Green’s function on a
2-D grid via FFT-based convolution (compute_green_function at
0x0808c350, fft_setup, fft_apply_to_green). For the
clean-room Python port we instead evaluate the integral on demand
with scipy.integrate.quad. This trades performance for
clarity: per-pair evaluation is ~10 ms vs the FFT’s amortised
~10 μs. For research-scale spirals (≤ 100 segments) the cost is
manageable.
The implementation here is the quasi-static limit: we drop
e^{-jk_z|z|} factors and compute the static Green’s function
G_qs(ρ) = (1/4πε₀ε_eff) · 1/sqrt(ρ² + h²) enhanced by the
multi-layer reflection-coefficient kernel. This captures the
substrate-coupled capacitance with reasonable accuracy at the
megahertz-to-low-GHz range without incurring the full Bessel-
function integration cost.
- reasitic.substrate.green.propagation_constant(k_rho, omega_rad, sigma_S_per_m)[source]¶
Complex propagation constant for one substrate layer.
Mirrors the binary’s
complex_propagation_constant_aand_b(decomp addresses0x0809421cand0x08094268):\[\gamma = \sqrt{k_\rho^2 + j \, 2\pi\mu_0 \sigma \omega}\]The square root is the principal complex sqrt (positive real part), matching the convention of the libstdc++
sqrt(complex)used in the binary.
- reasitic.substrate.green.green_oscillating_integrand(k_rho, omega_rad, sigma_a_S_per_m, sigma_b_S_per_m, layer_thickness_m, rho_m)[source]¶
Sommerfeld integrand with an oscillating
cos(k·ρ)factor.Mirrors
green_oscillating_integrand(decomp0x080937cc) — thecode *plugged into QUADPACK’s DQAWF cosine-weighted driver. Combines two layer propagation constantsγ_a/γ_b(computed viapropagation_constant()) with atanh(γ_a · t)boundary factor, then returns the rational expression that — once multiplied bycos(k_ρ ρ)and integrated over k_ρ — gives the layered-substrate Green’s function in the cosine-transform form.- Parameters:
k_rho (float) – Radial wavenumber (1/m) — the integration variable.
omega_rad (float) – Angular frequency (rad/s).
sigma_a_S_per_m (float) – Conductivity of layer A.
sigma_b_S_per_m (float) – Conductivity of layer B.
layer_thickness_m (float) – Thickness of the bottom layer (m).
rho_m (float) – Source-field horizontal separation (m).
- Return type:
- reasitic.substrate.green.green_propagation_integrand(k_rho, omega_rad, sigma_a_S_per_m, sigma_b_S_per_m, layer_thickness_m, z_m)[source]¶
Sommerfeld integrand with an exponential
e^{-γ z}propagation factor.Mirrors
green_propagation_integrand(decomp0x08093b34). Likegreen_oscillating_integrand()but with a vertical decay factor for the field point at heightzabove the substrate stack rather than a horizontal cosine modulation.
- reasitic.substrate.green.green_function_kernel_a_oscillating(k_rho, *, omega_rad, sigma_a_S_per_m, sigma_b_S_per_m, layer_thickness_m, z_m)[source]¶
Green’s-function inner kernel with the
2^{-k h / ln2}damping factor.Mirrors
green_function_kernel_a_oscillating(decomp0x080948d0). Multipliesgreen_oscillating_integrand()byexp(-k_ρ z)/k_ρ(the2^{-k·z / ln 2} / kfactor in the binary, which is just a cleverf2xm1 / fscale-friendly form ofe^{-k·z}/k). Returns the real part because the QUADPACK driver only consumes that.
- reasitic.substrate.green.green_function_kernel_b_reflection(k_rho, *, omega_rad, sigma_a_S_per_m, sigma_b_S_per_m, layer_thickness_m, z_m)[source]¶
Green’s-function inner kernel with the substrate reflection factor.
Mirrors
green_function_kernel_b_reflection. Uses thelayer_reflection_coefficient()Γinstead of the direct-source kernel, giving the image contribution to the layered-substrate Green’s function. Returns the real part.
- reasitic.substrate.green.green_function_select_integrator(integrand_kind, omega_rad, *, lower=0.0, upper=inf, integrand_args=None)[source]¶
Adaptively choose between the cosine-weighted and infinite-range Sommerfeld integrators.
Mirrors
green_function_select_integrator(decomp0x080949dc): if|omega| ≥ 1e-10the binary uses QUADPACK’s DQAWF (cosine- weighted Fourier integrator) on the oscillating-integrand path; otherwise it uses DQAGI (infinite-range adaptive integrator). The result is then multiplied by-μ₀ · ωto produce the final contribution to the substrate Green’s function.The Python equivalent uses
scipy.integrate.quad()for both paths since scipy’s quad handles oscillation and infinite ranges adaptively. Returns-μ₀ · ω · ∫ integrand dk.- Parameters:
integrand_kind (str) –
"oscillating"or"propagation"— selects which integrand to evaluate (seegreen_oscillating_integrand()andgreen_propagation_integrand()).omega_rad (float) – Angular frequency.
lower (float) – Integration limits.
upper (float) – Integration limits.
integrand_args (dict[str, float] | None) – Extra keyword arguments forwarded to the chosen integrand (sigma_a/b, layer_thickness, rho_m / z_m).
- Return type:
Region-independent (Coulomb-like) static term of the substrate Green’s function.
Mirrors
green_kernel_shared_helper_a(decomp0x0808f80c) and its sister_b(0x0808f004). The two share the same static body but accept slightly different argument layouts in the binary; in our cleaner Python API we collapse them to a single function. Returns the1 / (4 π ε₀ √(ρ² + (z_a + z_b)²))image contribution at lateral wavenumberk_ρ.
- reasitic.substrate.green.green_kernel_a_helper(k_rho, z_a_um, z_b_um, *, omega_rad=0.0, sigma_S_per_m=0.0)[source]¶
Above-source region kernel helper.
Mirrors
green_kernel_a_helper(decomp0x0808fc04). For the field point above the source layer this is the direct Coulomb kernel1/rplus a substrate-induced loss termRe(γ) · e^{-k(z_a+z_b)}.
- reasitic.substrate.green.green_kernel_b_helper(k_rho, z_a_um, z_b_um, *, omega_rad=0.0, sigma_S_per_m=0.0)[source]¶
Below-source region kernel helper.
Mirrors
green_kernel_b_helper(decomp0x0808f3f0). For the field point below the source: direct kernel minus the substrate reflection loss term. Sister ofgreen_kernel_a_helper().
- reasitic.substrate.green.green_function_kernel_a(k_rho, *, z_a_um, z_b_um, omega_rad=0.0, sigma_S_per_m=0.0)[source]¶
Top-level Sommerfeld integrand for the above-source region.
Mirrors
green_function_kernel_a(decomp0x0808cc90) — the 3637-byte top-level integrand for the above-source half of the layered Green’s function. Combinesgreen_kernel_a_helper()with the propagation factor.
- reasitic.substrate.green.green_function_kernel_b(k_rho, *, z_a_um, z_b_um, omega_rad=0.0, sigma_S_per_m=0.0)[source]¶
Top-level Sommerfeld integrand for the below-source region.
Mirrors
green_function_kernel_b(decomp0x0808dad4). Sister togreen_function_kernel_a()for the below-source half of the layered Green’s function.
- reasitic.substrate.green.layer_reflection_coefficient(k_rho, omega_rad, sigma_S_per_m)[source]¶
Substrate reflection coefficient for one Bessel mode.
Mirrors
reflection_coeff_imag(decomp0x08093eb8) but returns the full complex coefficient instead of just its imaginary part — callers can take.imagwhen they need to match the binary’s narrowed return.\[\Gamma(k_\rho) = \frac{k_\rho - \gamma(k_\rho)} {k_\rho + \gamma(k_\rho)}\]where
γispropagation_constant(). Verified against the C decomp:line 13100:
local_24 = k * k(sets upz = k²)line 13101:
local_2c = DAT_080ceb40 * 7.895683520871488e-06 * omega(imaginary part of γ²;DAT_080ceb40is the substrate conductivity σ at this layer, and7.895683520871488e-06is2π·μ₀in SI — seeTWO_PI_MU0)line 13105:
sqrt(complex)evaluatesγ = √(k² + j·2π·μ₀·σ·ω)lines 13106-13110: builds
(k − γ)and(k + γ)then complex-divides to give Γ; the C narrows the return toΓ.imag.
At the static limit
ω → 0(orσ → 0),γ → kand thereforeΓ → 0— the C model has no static stack reflection.
- reasitic.substrate.green.green_layer_tanh_factor(k_rho, dz_um)[source]¶
Layered-Green’s tanh boundary factor:
tanh(k_ρ · Δz).Mirrors the inner
(2^x − 1) / (2^x + 1) × signcomputation thatgreen_function_kernel_a(decomp0x0808cc90, lines 9630-9669) performs three times for different layer-boundary distances. The C builds it via the x87f2xm1/fscaleinstructions that compute2^x − 1directly:lVar15 = k_rho * (g_capacitance_options[p3] - z_obs); // = k·Δz lVar11 = 1.4426950408889634 * -ABS(lVar15 + lVar15); // = -2|k·Δz|/ln(2) // f2xm1+fscale: lVar14 = 2^lVar11 - 1 = exp(-2|k·Δz|) - 1 lVar11 = 1.0; if (-lVar15 < 0.0) lVar11 = -1.0; // sign of Δz dVar1 = (lVar14 / (lVar14 + 2.0)) * lVar11;
Algebraically with
u = exp(−2|k·Δz|):(u − 1) / ((u − 1) + 2) = (u − 1) / (u + 1) = −tanh(|k·Δz|)
Multiplied by
sign(Δz), the result istanh(k_ρ · Δz)— the standard layered-substrate tanh boundary factor at one interface. The C-side magic constants (0x080c8080 = -1.0,0x080c8090 = 2.0,0x080c80d0 = 0.0,0x1.71547652b82fep+0 = 1.4426950408889634 = 1/ln 2) are included in the rodata at the listed addresses.
- reasitic.substrate.green.green_function_static(rho_um, z1_um, z2_um, tech)[source]¶
Quasi-static substrate Green’s function value, in V/C.
rho_umis the lateral separation;z1_um/z2_umare the two source heights above the substrate. The result has units of inverse capacitance per length and is what gets convolved with the metal charge distribution to get coupled capacitances.For the full Sommerfeld integral (which this stub approximates via the leading 1/ρ kernel plus a layered reflection enhancement) we evaluate
\[G(\rho, z_1, z_2) = \frac{1}{4\pi\varepsilon_0} \bigl( \frac{1}{r_+} + R_\text{stack}(\rho)\,\frac{1}{r_-} \bigr)\]where
r_± = sqrt(ρ² + (z₁ ∓ z₂)²).For
rho_um → 0and same-layer pairs (z₁ = z₂) the direct 1/r_+ term diverges. Callers that need a singular self-term (e.g. a same-tile diagonal in the per-segment cap matrix) should userect_tile_self_inv_r()to compute the analytical finite-rectangle ⟨1/r⟩ instead. This function regularises the singular point with a 1 µm floor so it stays finite, but the floor is conservative (much smaller than typical tile sizes) and will overshoot the diagonal value if used as-is.
- reasitic.substrate.green.rect_tile_self_inv_r(width_um, length_um)[source]¶
Average of
1/rover a uniformly-charged rectangular tile.Returns the finite, non-singular self-overlap integral
\[\langle 1/r \rangle_\text{self} = \frac{1}{(ab)^2} \int_0^a\!\int_0^a\!\int_0^b\!\int_0^b \frac{1}{\sqrt{(x-x')^2 + (y-y')^2}} \,dx\,dx'\,dy\,dy'\]in units of 1/m. Multiplied by
1/(4πε₀)it gives the average potential per unit charge for the tile, which is the correct diagonal entry of the MoM potential matrix.Closed form (Nabors-White 1991, Walker 1990):
\[\frac{4}{3 a^2 b^2}\, \bigl[ -a^3 - b^3 + (a^2+b^2)^{3/2} + 3 a^2 b \sinh^{-1}(b/a) + 3 a b^2 \sinh^{-1}(a/b) \bigr]\]Both
width_umandlength_umare in microns.
- reasitic.substrate.green.coupled_capacitance_per_pair(rho_um, z1_um, z2_um, a1_um2, a2_um2, tech)[source]¶
Mutual capacitance between two finite metal patches.
The patches lie at heights
z1/z2with footprint areasa1/a2and lateral separationrho(centre-to-centre). Returns C in farads.Uses the static Green’s-function value evaluated at
ρas the inverse-distance kernel; for self-capacitance (ρ → 0) one of the patches’ size becomes the regularising radius — we useρ ← max(ρ, sqrt(a1)/π)to avoid the singularity.
- reasitic.substrate.green.integrate_green_kernel(rho_um, z1_um, z2_um, tech, *, k_max=100000000.0)[source]¶
Sommerfeld-style numerical Bessel-J0 integral.
Numerically evaluates
\[\int_0^{k_\text{max}} \frac{1}{k_\rho} R_\text{stack}(k_\rho) J_0(k_\rho \rho_m) e^{-k_\rho (z_1 + z_2)}\, dk_\rho\]via
scipy.integrate.quad(). Thee^{-k_ρ z}factor provides convergence at largek_ρfor anyz > 0.Returns a single-frequency, single-pair value in 1/m. Used by callers that want a more accurate (per-pair, slow) estimate than
green_function_static().
FFT-accelerated convolution of the substrate Green’s function.
Mirrors the binary’s full FFT pipeline:
compute_green_function()↔compute_green_function(decomp0x0808c350)fft_apply_to_green()↔fft_apply_to_green(0x080912c0)setup_green_fft_grid()↔fft_setup(0x08091548)rasterize_shape()— used byanalyze_capacitance_polygonto map a shape footprint onto the FFT charge gridsubstrate_cap_matrix()↔analyze_capacitance_driverend-to-end pipeline
The static substrate Green’s function G(ρ, z₁, z₂) only depends
on the lateral separation (Δx, Δy) between source and field
points. With the spatial-domain Green’s tabulated on an
(Nₓ, Nᵧ) grid, applying it to an arbitrary charge distribution
becomes a 2-D convolution, which the FFT performs in
O(Nₓ Nᵧ log(Nₓ Nᵧ)). For an M-shape capacitance-matrix
extraction this gives O(M · Nₓ Nᵧ log(Nₓ Nᵧ)) versus
O(M² · N_pairs) for the per-pair Sommerfeld integration in
reasitic.substrate.green.
The implementation builds the Green’s function directly in k-space
(spatial-frequency domain), where the layered-stack reflection
coefficient R_eff(k_ρ) has its natural definition. Linear
convolution is achieved by zero-padding the charge distribution to
(2Nₓ, 2Nᵧ) so wraparound aliasing is suppressed. This matches
the binary’s fft_apply_to_green which operates on the same
zero-padded layout (the literal nx*2 * ny*2 * 16 allocation in
the decompilation gives it away).
- class reasitic.substrate.fft_grid.GreenFFTGrid[source]¶
Bases:
objectPre-computed FFT-domain Green’s function for one
(z₁, z₂)pair.All arrays are zero-padded to
(2 N_x, 2 N_y)so the convolution implemented byfft_apply_to_green()is linear rather than circular.
- reasitic.substrate.fft_grid.setup_green_fft_grid(tech, *, z1_um, z2_um, nx=None, ny=None, chip_x_um=None, chip_y_um=None)[source]¶
Pre-compute the substrate Green’s function on a 2-D FFT grid.
Mirrors the binary’s
fft_setup(decomp0x08091548).The grid uses the
chipx/chipyextents andfftx/fftyresolution from the tech file by default; pass overrides for any of those to deviate.nx/nyshould be powers of 2 for the fastest FFT, but any positive integers are accepted.The resulting
GreenFFTGridcan be passed tofft_apply_to_green()for fast batched evaluation.
- reasitic.substrate.fft_grid.compute_green_function(tech, *, z1_um, z2_um, nx=None, ny=None)[source]¶
Public binary-equivalent entry point for
compute_green_function.Mirrors the binary’s top-level Green’s-function builder (
decomp/output/asitic_kernel.c:9203, address0x0808c350). Convenience alias ofsetup_green_fft_grid()so the API matches the C symbol name 1:1.
- reasitic.substrate.fft_grid.green_apply(grid, charge)[source]¶
Backward-compatible alias for
fft_apply_to_green().- Parameters:
grid (GreenFFTGrid)
charge (ndarray)
- Return type:
- reasitic.substrate.fft_grid.fft_apply_to_green(grid, charge)[source]¶
Convolve a charge grid with the precomputed Green’s function.
Mirrors
fft_apply_to_green(decomp0x080912c0). The charge grid is zero-padded to(2 N_x, 2 N_y)before multiplication so the convolution stays linear (no wraparound).- Parameters:
grid (GreenFFTGrid) – A
GreenFFTGridfromsetup_green_fft_grid().charge (ndarray) – An
(N_x, N_y)real array (Coulombs / cell). Must matchgrid.nx×grid.nyexactly.
- Returns:
The potential
Vin Volts, shape(N_x, N_y).- Return type:
- reasitic.substrate.fft_grid.rasterize_shape(shape, *, nx, ny, chip_x_um, chip_y_um)[source]¶
Mark grid cells covered by
shape’s polygon footprint.Returns a boolean
(N_x, N_y)mask. Used by the capacitance-matrix pipeline to turn a list of shapes into the charge grid that drivesfft_apply_to_green(). Mirrors the binary’sanalyze_capacitance_polygonrasterisation step.Each grid cell is treated as covered if its centre lies inside any polygon of the shape. Open (line) polygons are ignored.
- reasitic.substrate.fft_grid.substrate_cap_matrix(shapes, tech, *, z1_um=None, z2_um=None, nx=64, ny=64)[source]¶
End-to-end FFT-accelerated substrate capacitance matrix.
Mirrors the binary’s
analyze_capacitance_driver(decomp0x08052c50). ForMshapes returns an(M, M)symmetric capacitance matrix in Farads:Rasterise each shape onto the
(N_x, N_y)grid.Compute the Green’s function on the same grid.
For each shape
i, place uniform unit-charge on its footprint, propagate viafft_apply_to_green()to get the potential everywhere, and integrate over each shapejto form the potential matrixP_ij.Invert
Pto get the cap matrixC = P⁻¹.
The pipeline is symmetrised at the end to absorb numerical noise.