The solver & accuracy
antennaknobs solves antennas with momwire, an in-house method-of-moments (MoM) engine for wire structures, with an optional NEC-2 backend for cross-checking.
Basis functions
Section titled “Basis functions”momwire offers two current-expansion basis families in one engine — uncommon among free tools, where basis quality is usually a paid feature — plus a third TESTING rule (razor, below) on the tent expansion the B-spline family’s own degree-1 case already uses:
- B-spline — a degree-1/2 Galerkin basis, the default (degree 2),
- sinusoidal — a NEC-2-style three-term basis, point-matched like NEC-2; useful as a cross-validator (it tracks PyNEC closely because it shares both the basis and the point matching),
- sinusoidal-galerkin — the same three-term basis with Galerkin
(integrated) test rows: exactly reciprocal Z by construction, markedly
faster reactance convergence on junction-heavy geometry, and junction-node
ports (free space; PEC since momwire#191). It exists so basis effects and
testing effects can be told apart — the full story is
momwire’s chapter 15.
It also carries the one user-facing feed-model choice:
Converged (the default zero-width gap — converges to the B-spline
answer, exactly reciprocal Y) or NEC-compatible (a segment-wide gap —
NEC’s own source, including the reactance drift as the mesh refines).
It is the “feed model” control in the Sin-Galerkin slot’s gear menu (the
B-spline family carries the same control, defaulting to Converged), and
the workbench is the only place it is offered: the CLI and both momwire
portals carry one
sinusoidal-galerkinname, and it is the converged one (momwire#654). Reach for NEC-compatible when you want NEC’s source specifically — but for cross-checking against NEC, prefermomwire:sinusoidal, which is NEC-2’s whole formulation rather than just its feed. Converged is what near-open high-Q feeds want, and the workbench recommends it on the designs that need it — momwire#213 measured it removing 992×/374× of the cross-basis disagreement onlazy_h/vbeam, without reducing the mesh those designs genuinely need. The plainsinusoidalsolver offers no such choice: a zero-width gap cannot be expressed under point matching (momwire#212).
Plus two accelerated solvers for large problems:
hmatrix— ACA / hierarchical-matrix, sub-quadratic on large single-wire structures,arrayblock— element-aware block-low-rank, near-linear on arrays of identical / few-shape elements.
And one formulation twin:
razor-2p— a tent basis tested by NEC-5’s own razor-blade rule rather than point matching or Galerkin testing — see below.
Razor: the NEC-5 formulation twin
Section titled “Razor: the NEC-5 formulation twin”razor-2p is RazorSolver’s only --basis roster name (razor-nec5 is
its deprecated spelling) — the way bspline-d1 is BSplineSolver on a
bound degree. Unknowns are the same interior-knot tent basis bspline-d1
uses, but the row equations come straight from the public NEC-5 manual’s
mixed-potential method — the E-field boundary condition enforced on path
integrals between element centroids (“razor-blade” testing), not point
matching and not Galerkin testing. That makes it a formulation twin: a
way to reproduce NEC-5’s own convergence behaviour, including its
well-known O(1/N) reactance walk, without the licensed NEC-5 binary.
razor-2p binds NEC-5’s identified quadrature rule for the one path
integral the manual leaves numerically open (nec5_quadrature); the
class’s other quadrature — the default, converged Gauss-Legendre lane — is
not a --basis name. It left the CLI roster in momwire#753 (2026-09-02,
“a roster entry is a menu item that must be worth ordering”, momwire#654)
and is reached only by constructing RazorSolver(...) directly; the walk
it shows is the testing rule’s own discretization error rather than a
quadrature shortfall.
razor-2p is the orderable lane. It binds the two-point rule
momwire#316 identified for the testing-path integral, where the
unrostered Gauss-Legendre lane spends roughly 10× the wall time on
quadrature nodes for an advantage that has evaporated by N≈192.
The name describes that rule rather than another vendor’s product, and the change is deliberate (momwire#785). Two things are true at once here, and it is worth keeping them apart:
- At a working mesh it does track NEC-5, because it reproduces NEC-5’s testing formulation and therefore its discretization behaviour — measured against the licensed binary at 0.003–0.007 Ω across the drop-in’s ladder (momwire#603). That is the whole reason the lane exists.
- It is not converging somewhere different. The limit it walks toward is
the same one
bspline-d2reaches, and it gets there more slowly — roughly 16× the mesh for the same self-convergence on the ByDipole1 ladder. So the old name’s implication, that this lane is accurate because it is NEC-5’s, is the part that does not survive: it reproduces a formulation, not a privileged answer.
If reproducing that formulation is not your question, bspline-d2 is the
better answer. razor-nec5 still works as a deprecated alias.
The Gauss-Legendre lane came first — it was built as the twin, before
momwire#316’s residue study identified the two-point quadrature rule that
made the match near-exact — and what it is now is an instrument, not a
roster choice: it answers “is this coarse-mesh disagreement the testing
rule or NEC-5’s quadrature shortcut?”, and nothing a model needs, which is
why momwire#753 (2026-09-02) dropped it from the CLI --basis roster —
reach it by constructing RazorSolver(...) directly. It costs about 20×
the time for that (free space at N=1600, one box, momwire 0.44.0: 20.2 s
against razor-2p’s 0.97 s) and, since momwire#742 gave both lanes the
same fill, essentially the same memory (520 MB against 479 MB). At a fine
mesh the two agree to 0.001 Ω, so the quadrature question it exists to
answer is a coarse-mesh one. The measured two-lane table lives on
momwire’s engine-choice page.
Refusal boundary. RazorSolver is deliberately scoped to what its formulation-twin role needs, and refuses the rest at construction with a named message rather than a silent wrong answer:
- No extended kernel — it is reduced-kernel only; NEC-5’s formulation tests the expansion on the wire axis, and extending it would answer a different question than the one this solver exists to check.
- No junction ports, no node gaps — a junction basis is already a through-current unknown with no unambiguous branch to drive a source or land a series gap on. Ordinary K=2 junctions (a wire split, or two wires meeting end to end) are unaffected — those resolve to the same tent basis automatically, from the geometry, with nothing to configure.
- No ground contact over a finite ground (issue #282) — over both
finite-ground flavours, an end resting in the plane would need its
grounded-end tent’s image wing to carry spurious contact charge, since
the fold hard-codes image coefficient 1 (PEC). Ground contact over a
PEC plane (
ground=pec) is fully served — including a base-fed monopole. - No K≥3 port, on a feed, load, or junction — the branch pair a source or load would drive is ambiguous at three or more coincident ends.
Free space and all three grounds (PEC, reflection-coefficient, Sommerfeld)
are otherwise served, along with per-wire radii and both distributed and
lumped wire loading. Full detail: momwire’s
docs/razor-solver.md.
The extended thin-wire kernel (EK)
Section titled “The extended thin-wire kernel (EK)”Every basis above solves a thin-wire integral equation: the current is
treated as a filament on the wire axis, and the field is matched on the
surface. That approximation is excellent while each segment is long compared
to the wire’s radius, and it degrades as the ratio Δ/a falls — the same
axis that produces
convergence failure class 4.
NEC’s answer is the extended thin-wire kernel — the EK card — which
replaces the on-axis Green’s function with an O(a²) expansion integrated over
the tube. The correction is a fraction of a percent at Δ/a > 10 and several
percent below Δ/a ≈ 3, and it moves the answer toward NEC’s: on a Δ/a = 2.27
dipole, nec2c reads 123.7+28.6 j reduced and 113.6+29.0 j extended — an 8 %
step — and momwire’s sinusoidal basis tracks both sides of the card to 0.5 %
and 3.1 % respectively.
momwire serves it on five of the six solver families — sinusoidal,
sinusoidal-galerkin, bspline, hmatrix and
arrayblock — in free space and over every ground model, at about
1.0–1.3× the reduced-kernel solve. The Galerkin family joined with momwire
0.27.0: momwire#246 built its extended kernel, momwire#287 measured the
Sommerfeld ground in, and momwire#299 made non-collinear geometry (vees,
bent elements, junctions, radius steps) sound. Two things refuse it,
loudly rather than silently:
RazorSolver(razor-2p, and its unrostered Gauss-Legendre quadrature) — reduced-kernel only, by design: NEC-5’s formulation is the comparison target, and it tests the expansion on the wire axis. See Razor above.- singular enrichment, on the bases that otherwise serve EK — the enrichment degrees of freedom carry their own quadrature and bypass the moment kernels the extended kernel corrects (momwire#249).
Three ways to ask for it: the extended kernel (EK) check in a solver
slot’s gear menu (per slot, so you can put the same basis and mesh in two
slots and read the difference); --extended-kernel on the CLI; or an EK
card in an imported deck, which is honoured on its own. Reach for it on thick
elements — tubing, cages, fat-wire imported decks — and when cross-checking a
NEC model whose deck carries the card. On ordinary thin wire, leave it off:
it changes the answer by less than the mesh does.
Which solver should I use?
Section titled “Which solver should I use?”The selection matrix, the runtime findings (the ground-cost ladder, where
the accelerated engines win and where they lose), the memory envelopes,
and the fixed-accuracy census verdict behind the bspline d=2 default all
live on momwire’s own engine-choice page — one home per fact, keyed to the
same engine names the workbench’s --basis control takes:
Two app-side notes the engine page doesn’t carry:
- PyNEC’s role here is the independent NEC-2 reference riding alongside: a great fast cross-check on small/medium single structures, but not universally fast — it loses the log-periodic on every ground model (free space: 14 s vs ArrayBlock’s 1.2 s), so “use PyNEC as the reference” holds for small designs, not arrays.
- Junction-port (
PortAtEnd) designs acceptsinusoidal-galerkinas the second opinion (historically B-spline-only; the sin-Galerkin junction ports run in free space and over a PEC ground — momwire#191 — with finite grounds still refused).bsplineremains the default.
Segments & convergence
Section titled “Segments & convergence”Method-of-moments discretizes each wire into segments, and the solve builds one basis function per segment. The segments / wire (N) control in the workbench sets the design’s mesh density: every wire gets N segments per quarter-wavelength (at the design frequency), so a long radiator gets proportionally more segments than a short stub — and N means the same physical segment length on every design (N=15 ≈ λ/60). The total basis-function count — the sum across every wire — is the dimension of the impedance matrix the solver fills and factors.
That matrix is what sets both accuracy and cost:
- Too few segments and the current distribution is under-resolved — the feed-point impedance hasn’t converged and your SWR/resonance readings are off, sometimes by a lot near a sharp feature.
- More segments refine the answer, but the dense solvers form an N×N matrix: memory grows as N² and fill/factor cost as N²–N³. Past the point where the impedance stops moving, the extra segments only cost time.
Finding “enough” — the convergence sweep
Section titled “Finding “enough” — the convergence sweep”The workbench’s convergence sweep re-solves the current antenna across a range of N and plots the resulting feed-point impedance R + jX against N. Read it like any convergence study: the curve drops steeply at small N, then flattens (“the knee”). The smallest N past the knee is your sweet spot — converged, but no slower than it needs to be. If the curve never settles, the geometry may have a feature (a tight bend, a very short feed gap) that needs finer local segmentation, or a different basis.
A quick rule of thumb: the dense bases want enough segments per half-wavelength to resolve the sinusoidal current — a couple of dozen across a half-wave element is typical. The convergence sweep turns that rule into an answer you can see for your antenna.
For the full method — convergence ladders, cross-basis validation (a flat curve can be flat at the wrong value), and the four distinct reasons a curve refuses to settle — see the advanced guide: How many segments?
The size cap
Section titled “The size cap”Because the dense matrix grows as N², a runaway segment count (or a big array)
can allocate hundreds of megabytes and stall a solve. The hosted instance
therefore caps the total segment count and rejects oversized solves with a
clear message rather than melting the shared box. The cap is engine-aware: the
compressed arrayblock / hmatrix engines skip the dense matrix
(ACA / H-matrix), so they’re allowed a much higher count — which is exactly why
they exist for large arrays. The cap is off by default and enforced only on
the shared hosted instance — a local pip install is uncapped; the toggle and
the limits are env-configurable (see docs/deploy.md).
Accuracy & validation
Section titled “Accuracy & validation”- A NEC-2 reference engine (
pynec-accel) runs alongside momwire — and a licensed NEC-5 can make it a three-way triangle — so any design can be solved two ways and compared — a built-in sanity check most tools lack. - The repo carries the benchmark above plus per-design solver comparisons.
Honest limitations
Section titled “Honest limitations”In the spirit of not overselling: momwire wires are PEC by default; designs
that declare a wire material (the WIRES catalog — see the
wire-gauge example) get skin-effect conductor loss as
a distributed series impedance in the solve itself (momwire ≥ 0.10.0, validated
against NEC’s native LD 5 wire-loss card to ~0.5 %) plus the insulated-wire
velocity factor (mirrored on the NEC engine as an LD 2 distributed-inductance
card, agreeing on the resonance shift to ~1 %). Every momwire solver carries
the loading (momwire ≥ 0.11.0): the B-spline family as a Galerkin overlap, the
sinusoidal solver through NEC’s impedance boundary condition at its match
points — so matched-basis cross-engine comparisons keep the full wire physics
on both sides. Finite grounds are
solved with a true Sommerfeld/Norton model on every momwire solver
(momwire ≥ 0.8.0: NEC’s exact-image-plus-remainder decomposition; the
accelerators carry the smooth remainder as one global low-rank term on their
fast paths). Validation against an independent NEC-2 implementation across
0.02–0.5λ heights — including the very-low region where
reflection-coefficient models are tens of ohms off — lands within ~2.4 Ω on
the B-spline basis and ~0.1 Ω on the sinusoidal basis (which shares NEC’s
basis, making it the sharpest check of the model). The faster
reflection-coefficient model remains the default and the NEC path offers its
own Sommerfeld–Norton — so real-ground results cross-check across two
independent engines at every height.
Grazing heights (momwire ≥ 0.39.0): a wire very close to a finite ground
— an elevated radial system, a ground screen, a low horizontal run — used to
get worse with mesh refinement rather than better, which is the signature
of a numerical defect rather than a modelling limit. It was two of them, in
two different places, and both are fixed. Against captured reference
printouts of the same 1.832 MHz radial system standing 1.8 cm (1.09e-4 λ)
above earth, the served impedance moved from 275 Ω and 188 Ω away to
12.3 Ω and 5.2 Ω, the pattern peak now lands in exactly the captured
direction with the level inside 0.3 dB, and — the tell that matters — two
different meshes of that one antenna now agree with each other to 0.6 Ω
where they previously disagreed by 100 Ω. Both the default bspline lane
and the NEC-5 formulation twin are fixed, so the cross-check at grazing
height is a genuine second opinion rather than two copies of one bug.
Two things to know about the edges. Standing a wire in a finite ground —
ground contact, as distinct from grazing above it — is served on the
bspline lane only, at about 7 % on impedance; the formulation twin refuses
it by name rather than guess
(momwire#624). And the
accelerated solvers (HMatrixSolver, ArrayBlockSolver) reach the ground
image by their own path and have not received the grazing fix
(momwire#634) — they
are accurate at ordinary heights and should not be selected for a grazing
model; the default solver is unaffected.
Below the interface (momwire ≥ 0.38.0): wires strictly below the ground
plane — buried radials and screens, buried fed elements, elevated feeds over
buried counterpoises — serve impedance, currents and charges on the
bspline lane over the Sommerfeld ground. Since momwire 0.41.0 a wire may
also cross the interface at a declared junction: a buried wire whose end
stands in the ground plane, junction-joined there to one above-ground wire
(one above × N below, so a connected radial screen spells as N rises meeting
the monopole at the surface, and a buried hub joining the radials at depth
is allowed). The design catalog now authors buried
geometry directly — a buried-radial vertical, an elevated counterpoise over
buried radials, and a buried dipole — with their own in-medium meshing
(medium-aware auto-meshing in the builder at large remains
antennaknobs#983).
What still refuses does so by name: a wire crossing the interface mid-span,
a ground-contact wire combined with buried wires (the rise respelling is
the served path), and near fields or patterns of buried decks. Validation
below ground rests on exact identities (the lossless-limit collapse onto
free space, the deep-burial limit onto the infinite-medium solve) plus
ladder-limit agreement at the half-percent class on the radial and
counterpoise classes, with the with/without-radials coupling differential
matching to about a milliohm; and, where a licensed NEC-5 is asked with its
documented below-ground card, the two engines agree to a few percent on
wholly buried fed elements and on bonded-base verticals over buried radials
(the validation page carries the numbers). The
one buried spelling NEC-5 has no documented answer for is a conductor that
stops on the interface above buried wires, which momwire refuses by name on
its own physics. One cost note: a deck’s first buried solve builds its
below-interface Sommerfeld tables (C++-accelerated since momwire 0.39.0,
and cached on disk thereafter); crossing-junction pairs use a direct
designed evaluation whose C++ twin landed in momwire 0.41.0, so a
crossing-class solve runs in seconds warm.