Skip to content

Golden impedance matrix: eleven minimal decks and two CI jobs that gate on them (#15) - #22

Merged
maurymarkowitz merged 1 commit into
maurymarkowitz:mainfrom
stevenmburns:golden-impedance-matrix
Sep 16, 2026
Merged

maurymarkowitz merged 1 commit into
maurymarkowitz:mainfrom
stevenmburns:golden-impedance-matrix

Conversation

@stevenmburns

Copy link
Copy Markdown
Contributor

The CI matrix offered on #15: eleven minimal decks, one per feature axis, with pinned input impedances, a stdlib compare script, and two jobs appended to ci.yml. Nothing else in the workflow changes (37 lines added, none removed); both jobs reuse the onec-linux-openblas artifact build-linux already uploads, so they add no build.

What is in it

tests/golden_tests/:

Two jobs, both needs: build-linux:

job decks at acafb37
golden-impedance 01–10 green — twelve points pass, widest 4.0e-05 (05_ld5)
golden-open-issues 11 red by design until #14 closes — 79.228 +j4.256 against 91.758 +j13.222, 1.7e-01

The floor is the regression contract and stays green; the red lives in the second job and points at exactly one deck.

Where the pins come from

I had suggested a three-way agreement at 1e-4 on #15. Measured, that does not exist between NEC-2 transliterations: nec2c 1.3.1 and nec2++ (via PyNEC) land about 2e-4 apart on these decks, and an independent MoM code (momwire, NEC-2's sinusoidal basis) about 1 % away. So every pin is nec2c 1.3.1's printed value, corroborated by nec2++ to ~2e-4 and by momwire to ~1 %, and the 1e-4 gate is a regression tolerance against the pin, not a claim of absolute accuracy. onec itself sits 1e-6 to 4e-5 from nec2c on the floor decks. Deck 10 is two-way (nec2c + momwire) because PyNEC's gx_card path disagrees with its own explicit two-wire twin; deck 11 is three-way, and it is the tightest row in the matrix: nec2c, nec2++ and momwire inside 1e-3 of each other, onec 17 % away while echoing RELATIVE DIELECTRIC CONST.= 10.000 correctly — the Sommerfeld path runs and returns a wrong number, which is why the matrix pins impedances rather than only the echo.

Reproducing

python3 tests/golden_tests/run_golden.py --onec ./onec                                   # exit 0
python3 tests/golden_tests/run_golden.py --onec ./onec --expected tests/golden_tests/expected_open.json   # exit 1 until #14 closes

Parser notes for anyone extending the script: a TL/NT deck prints a STRUCTURE EXCITATION table with the same column shape as the input-parameters row, so the parser scopes to the ANTENNA INPUT PARAMETERS header; onec writes CRLF by default and packs negative fields without a separator, both handled.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KGphPpW5qvL51b5xXQ8m5i

Eleven minimal decks under tests/golden_tests/decks, one per feature axis, each
with a pinned input impedance, plus run_golden.py to check onec against them.

  01_dipole_free          free space, the anchor case
  02_gn1_pec              GN 1, perfectly conducting ground
  03_gn2_sommerfeld       GN 2 Sommerfeld, epsr=10 sigma=0.002, a wavelength up
  04_ld0_series_rlc       LD 0, a series RLC lump on one segment
  05_ld5_conductivity     LD 5, finite wire conductivity
  06_junction_three_wire  three wires meeting at one point
  07_tl                   TL, an ideal 50 ohm line between two dipoles
  08_nt                   NT, a two-port admittance matrix
  09_fr_sweep             FR stepped sweep, all three frequencies pinned
  10_gx_symmetry          GX reflection along X
  11_gn2_low_height       GN 2 at 0.02 lambda, the issue maurymarkowitz#14 residual

They run in two jobs against one script, so a red X names exactly one deck:

  golden-impedance    expected.json      decks 01-10, twelve points   GREEN
  golden-open-issues  expected_open.json decks on an open issue       RED

THE RED LIVES IN golden-open-issues, AND IT IS RED BY DESIGN. The floor job is
green at acafb37 with its widest row at 4.0e-05, and it must stay that way; the
open-issues job holds 11_gn2_low_height, which answers 79.228 +4.256j against a
pin of 91.758 +13.222j, 1.7e-01 out, and maps to the still-open issue maurymarkowitz#14. The
GN 2 sequential-path fix at 6a7a395 corrected the echoed environment block and
the far-field case (deck 03 passes at 4.0e-06), but the near-ground solution is
still wrong -- and deck 11 echoes RELATIVE DIELECTRIC CONST.= 10.000 correctly
while getting the answer wrong, which is exactly why this matrix pins
impedances and not just the echo. When maurymarkowitz#14 closes, move deck 11's entry from
expected_open.json into expected.json and the floor grows by one deck.

The provenance rule: every pin is nec2c 1.3.1's printed value, cross-checked
against two engines that share no code with it -- PyNEC (nec2++, an
independent transliteration of the same Fortran) and momwire 0.56.0 on its
sinusoidal basis (an independent method-of-moments code). Each deck's CM lines
carry the pin and the measured spread; PROVENANCE.md records what every engine
returned, so a pin can be audited rather than trusted. It also states plainly
what the tiers are: onec and nec2c agree to 1e-6 because they are the same
lineage, nec2++ to ~2e-4, momwire to ~1%. 1e-4 is a regression tolerance
against the pin, not a claim of absolute accuracy. Deck 11 is the tightest
three-way row in the matrix -- all three engines inside 9.5e-04 of each other,
with onec 1.7e-01 away from all three.

Deck 10 is pinned two-way, on nec2c and momwire: PyNEC's gx_card path returns
109.563 +50.807j where its own explicit two-wire twin returns 24.897 +67.353j,
so nec2++ gets the symmetric solve wrong and cannot serve as a third opinion
on that axis. nec2c's GX result is bit-identical to its own explicit twin.

run_golden.py is stdlib-only and Python 3.8 compatible. It parses every
ANTENNA INPUT PARAMETERS block, compares at 1e-4 relative on |Z - Z_exp| /
|Z_exp|, and exits 1 on a drifted impedance, a nonzero onec exit, or a missing
block, naming the deck. It also carries the guard that would have caught the
first half of maurymarkowitz#14: for a deck with a GN card, the echoed ANTENNA ENVIRONMENT
block must match the deck's own epsr and sigma.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGphPpW5qvL51b5xXQ8m5i
@maurymarkowitz
maurymarkowitz merged commit 02487db into maurymarkowitz:main Sep 16, 2026
4 of 5 checks passed
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.

2 participants