Add transmission-line parameters (Z0, C, attenuation, γ); derive substrate height from geometry#7
Merged
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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()incalcl.c): from each line's diagonal series R/L and the effective permittivity, reports effective εr, characteristic impedance Z0, capacitance C (viaLC = εeff/c²), conductor + dielectric attenuation, phase constant β and complex propagation γ. This is wherecalc_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_hwas 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 assignal.y − ground_top, so εeff/Z0 and L always refer to the same height. A legacysubstrate_h:key is parsed-but-ignored with a deprecation note.er/tan_deltaremain 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
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).Notes
🤖 Generated with Claude Code