Skip to content

Add transmission-line parameters (Z0, C, attenuation, γ); derive substrate height from geometry#7

Merged
osaether merged 4 commits into
mainfrom
transmission-line-params
Jun 8, 2026
Merged

Add transmission-line parameters (Z0, C, attenuation, γ); derive substrate height from geometry#7
osaether merged 4 commits into
mainfrom
transmission-line-params

Conversation

@osaether

@osaether osaether commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Summary

Gives the dielectric a physically meaningful effect on the output and cleans up a redundant input field, building on the existing PEEC R/L solver.

  • New per-line transmission-line section (calc_line_params() in calcl.c): from each line's diagonal series R/L and the effective permittivity, reports effective εr, characteristic impedance Z0, capacitance C (via LC = εeff/c²), conductor + dielectric attenuation, phase constant β and complex propagation γ. This is where calc_dielectric_loss()'s attenuation constant (1/m) finally lands — on the shunt side of the line, not folded into the Ω/m R matrix. The R/L/|Z| matrices are untouched.

  • Substrate height is now derived from geometry, not an input. The original 1995 Weeks code had no dielectric fields; substrate_h was an AI-era addition that duplicated a height the geometry already defines (the trace-to-ground gap), and the examples had the two disagree. substrate_height() (calcl.c) computes it as signal.y − ground_top, so εeff/Z0 and L always refer to the same height. A legacy substrate_h: key is parsed-but-ignored with a deprecation note. er/tan_delta remain inputs (genuine material properties).

  • Examples are now real microstrips: traces placed at their actual substrate heights (1.6 mm FR4, 0.813 mm Rogers) with 35 µm (1 oz copper) thickness.

  • New Z0 sanity-check harness (tools/microstrip_z0/, stdlib-only): cross-checks per-line Z0 against the Hammerstad-Jensen microstrip closed form. make check-z0.

Validation

  • FastHenry R/L crosscheck still passes (matrices unchanged by design): max diff 0.55–2.75%.
  • Z0 vs Hammerstad-Jensen: test_microstrip (thin-trace reference) agrees to ~0.03%; the real material examples land within the 10% sanity tolerance (single FR4 line +7.1% at 35 µm; residual is finite ground-plane width + thickness at w/h ≈ 0.09).
  • 25/25 Python unit tests pass; all six examples run clean; build is warning-free.

Notes

  • A thickness-corrected H-J variant was evaluated but not adopted — the Hammerstad width correction over-corrects at these narrow w/h ratios and diverges ~16% from the FastHenry-validated weeks result, so the zero-thickness reference is cleaner.
  • This is a single-line characterization (the quasi-TEM Z0 does not model inter-line capacitive coupling under an inhomogeneous dielectric — that would need a full electrostatic P-matrix solve).

🤖 Generated with Claude Code

osaether and others added 4 commits June 8, 2026 13:22
Surface the dielectric in a physically meaningful result. The series R/L
matrices are dielectric-independent, but calc_dielectric_loss() returns an
attenuation constant (1/m) that previously had nowhere to go. Add
calc_line_params() in calcl.c to compute per-line quasi-TEM transmission
parameters from the diagonal of the final impedance matrix: effective
permittivity, characteristic impedance Z0, capacitance C (via LC = eff_er/c^2),
conductor/dielectric attenuation, and complex propagation gamma / effective er.
The R/L/|Z| matrices are untouched, so the FastHenry crosscheck still passes.

weeks takes L from the conductor geometry but eff_er from substrate_h; when the
trace's geometric gap to ground does not match substrate_h, the reported Z0
mixes two heights, so calc_line_params() warns on stderr.

Add tools/microstrip_z0/, a stdlib-only harness that sanity-checks the per-line
Z0 against the Hammerstad-Jensen microstrip closed form (no external solver),
independently validating the PEEC inductance. It flags geometry mismatches the
same way. On the consistent examples/test_microstrip.yaml, weeks and H-J agree
to ~0.03%. Wire it up as `make check-z0` with unit tests under tools/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The dielectric layer (er/substrate_h/tan_delta, Hammerstad-Jensen eff_er,
dielectric loss) is not part of the original 1995 Weeks code -- it was added
later. substrate_h in particular duplicated a height the geometry already
defines: for a microstrip the substrate fills the trace-to-ground gap, which
the y-coordinates already encode. The two could (and in the shipped examples
did) disagree, making the per-line Z0 -- which combines L from geometry with
eff_er from substrate_h -- physically meaningless.

Remove substrate_h as an input and derive the substrate height from the
geometry instead (substrate_height() in calcl.c: signal y minus ground-plane
top). eff_er/Z0 and L now refer to the same height by construction, so the
geometry/substrate_h inconsistency -- and the warning added for it -- are gone.
A legacy substrate_h key is parsed but ignored with a deprecation note. er and
tan_delta remain inputs (genuine material properties).

- include/weeks.h: drop substrate_h field
- src/input.c: stop parsing substrate_h; emit deprecation note if present
- src/calcl.c: add substrate_height(); use it in calc_line_params(); remove the
  now-impossible geometry-mismatch warning and the stale stderr eff_er trace
- src/weeks.c: report the derived substrate height
- tools/microstrip_z0: use the geometric gap as the height; drop the
  gap-vs-substrate_h mismatch logic and --gap-tol
- examples/*.yaml: remove substrate_h; test_microstrip documents the geometry
- README: refresh scope (R/L dielectric-independent; Z0 section does use it)

R/L matrices unchanged (FastHenry crosscheck still passes); test_microstrip
agrees with Hammerstad-Jensen to ~0.03% (make check-z0); 25 Python tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The examples previously sat all signal traces at y=77µm (a ~75µm gap) while
labelling themselves 1.6mm FR4 / 0.813mm Rogers. Now that the substrate height
is the geometric trace-to-ground gap, move each trace to its intended height so
the examples model real microstrips:

- test.yaml, test_fr4.yaml, test_single.yaml: y = 1.602e-3 (1.6mm FR4)
- test_rogers4003.yaml: y = 0.815e-3 (0.813mm RO4003C)
- test_air.yaml: y = 1.602e-3 (matches test_fr4 geometry; air baseline, only er differs)

test_microstrip.yaml is left at its consistent 200µm. weeks still agrees with
FastHenry on R/L for the moved geometry (max diff <1%) and with Hammerstad-Jensen
on Z0 within the 10% sanity tolerance (single FR4 line: 171 vs 156 Ohm, +9.7%;
the residual is finite ground-plane width and trace thickness at w/h~0.09).
README illustrative snippet aligned to 1.6mm.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
35 µm (1 oz) is the common real-world PCB default; the examples used 18 µm
(½ oz). weeks models the trace thickness correctly -- FastHenry still confirms
R/L to <1% -- and against the zero-thickness Hammerstad-Jensen reference the Z0
sanity check actually agrees better at 35 µm (single FR4 line +9.7% -> +7.1%).

test_microstrip.yaml is deliberately left at 18 µm: its H-J reference is
zero-thickness, so a thin trace isolates the inductance comparison (~0.03%).
A thickness-corrected H-J was evaluated but not adopted -- the Hammerstad width
correction over-corrects at these narrow w/h ratios and diverges ~16% from the
FastHenry-validated weeks result, so the zero-thickness reference is cleaner.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@osaether osaether merged commit 3617e6e into main Jun 8, 2026
1 check passed
@osaether osaether deleted the transmission-line-params branch June 8, 2026 18:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant