Skip to content

PN Junction model from Sze - #2

Closed
mdmaas wants to merge 4 commits into
mainfrom
pn_junction
Closed

PN Junction model from Sze#2
mdmaas wants to merge 4 commits into
mainfrom
pn_junction

Conversation

@mdmaas

@mdmaas mdmaas commented Aug 26, 2026

Copy link
Copy Markdown
Member

Summary

Implements a PN-junction depletion model for the 2D TW-MZM workflow, replacing the hand-picked junction capacitance with textbook physics.

Formulas (Sze & Ng, Physics of Semiconductor Devices, 3rd ed., Wiley, ch. 2)

  • Built-in voltage: V_bi = (k_B T / q) ln(Na·Nd / ni²)
  • Abrupt-junction depletion width: W = sqrt(2·eps_s·(V_bi + V_R)/q · (Na+Nd)/(Na·Nd)), split asymmetrically x_p = W·Nd/(Na+Nd) into P and x_n = W·Na/(Na+Nd) into N
  • Linearly graded junction: W = [12·eps_s·(V_bi+V_R)/(q·a)]^(1/3) with grade constant a = |dN/dx|
  • Depletion capacitance: C_j = eps_s / W (per area), C = eps_s·A/W absolute

Doping concentrations use the industry-standard cm⁻³; lengths in µm.

User API

from gsim.common.stack.junction import PNJunctionConfig

junc = PNJunctionConfig(na_cm3=1e19, nd_cm3=1e19, v_reverse=0.0)
junc.w_um, junc.xp_um, junc.xn_um, junc.capacitance(length_um, height_um)

Two representation modes, auto-selected from W vs the flanking doped sections (high-res when W >= ~1/5 of the smaller flank, capacitance otherwise; manual override via mode=):

  • capacitance: geometry unchanged (adjacent P/N); computed C applied as a lumped Impedance boundary — one call: sim.set_pn_junction(junc, layer_p="p_rib", layer_n="n_rib", length_um=10.0, height_um=0.22)
  • high_res: contiguous depleted-Si dielectric strip of width W drawn between P and N on its own GDS layer and resolved on the actual mesh (pure real eps, no carriers); no lumped boundary

The profile builder returns doped regions, P/N regions, junction metadata (widths/capacitance/chosen mode):

pn = make_pn_junction_profile(comp, ..., junction=junc, p_region=("p_rib", (21,0), sigma),
                              n_region=("n_rib", (20,0), sigma),
                              junction_region=("junction", (22,0)), mode="auto")
pn["junction"]["mode"], pn["junction"]["c_f"]

Demo

The 2d_twmzm notebook now illustrates this: default doping (~1e19 cm⁻³, W≈17 nm) auto-selects capacitance mode (13.9 fF vs the previous hardcoded 1 fF), and a sweep shows W crossing the threshold into high-res mode.

Also fixed

  • build_doped_cross_section() never registered the merged doping/rib materials on stack.materials, so doped domains silently resolved to eps=1.0 without conductivity in generated Palace configs (visible in prior demo artifacts). Now registered, with regression test.

Tests

41 new tests: physics values/limits/scalings and error paths, profile geometry/materials/auto-mode boundary cases, and end-to-end Palace checks (Impedance Cs value in capacitance mode; junction dielectric domain group with eps=11.9/no conductivity in high-res mode).

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Aug 26, 2026
@mdmaas mdmaas closed this Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant