Skip to content

SimNEC round-trip

SimNEC (AE6TY) is the successor to SimSmith: a Smith-chart station tool with NEC2 embedded behind its own MNA circuit solver. antennaknobs speaks its native .ssn circuit file in both directions — export a design for SimNEC to solve, or load a SimNEC circuit as a design — so the same antenna and matching chain can be checked by two independently written solvers without hand-entering geometry or component values in either direction.

The element mapping is validated against a real SimNEC installation (5.1a0): generated stations load with correct values, reproduce the reference impedance, and survive a SimNEC load/save round-trip without drift.

Terminal window
# Antenna alone, free space
python -m antennaknobs.simnec_export dipoles.invvee --out invvee.ssn
# A whole station — feedline, tuner tee, and the antenna in one circuit
python -m antennaknobs.simnec_export wire.doublet_ladder_tuner --out station.ssn
# Over real ground, with an armed SimNEC frequency sweep
python -m antennaknobs.simnec_export loops.skyloop_lmatch \
--ground finite:13,0.005 --sweep 6.9,7.3 --out skyloop.ssn
# A NEC card deck converted straight to a SimNEC circuit
python -m antennaknobs.simnec_export @measured/invvee.nec --out invvee.ssn

From the workbench, with no terminal: open the Files view and pick the SimNEC tab. It holds the same circuit for the design on screen — its knobs, its frequency, its ground — with Copy and Download beside it, the way the Source and engine-deck tabs work. That is the whole export step on Windows, where the packaged workbench is the only interface there is. The tab is offered for every design and needs no engine installed; a design SimNEC cannot carry shows the same refusal the command prints, naming the construct in the way. The Generator’s frequency is the solve frequency and no sweep is armed — arming one is --sweep below, on the command line.

Flags: --freq (MHz, default the design’s), --ground free | pec | finite | finite:<eps_r>,<sigma> | mininec:<eps_r>,<sigma> (the last as SimNEC’s own MiniNECGround), --seg-per-wl (skip the per-wire mesh pin described below and ask for SimNEC’s own re-mesh at NECOptions.segmentsPerWavelength instead — for a convergence comparison against SimNEC’s own density), --sweep (bare for ±10% around the frequency, or LO,HI), --name, and --out (default stdout).

Antenna-only designs export as SimNEC’s canonical three-element circuit — LOAD / NETWORK / GENERATOR — with the geometry riding inside the NETWORK element as a NEC-portal script (the same GW/FR/EX/lumped-LD cards export emits, plus daemon directives for ground and mesh density).

SimNEC’s NEC2 reader ignores everything in that block but GW/GM/GS/EX/NT, so three more things travel as daemon directives rather than cards: the wire conductivity as one NECOptions.mhosPerMeter for the whole block (refused by name when the design’s wires do not all share one value); each wire’s mesh, as a $GW_<tag>.JamSegments(N) carrying the deck’s own segment count, so SimNEC solves the mesh you asked for instead of re-meshing it away — unless --seg-per-wl is given, which skips these and asks for SimNEC’s own density instead; and an insulation jacket, as NECOptions.Insulation("W7EL", thickness, εr, 0) — the EZNEC correction model, set inside if (NECOptions.Engine == 2) since it applies on SimNEC’s NEC2 engine only, with an errorOutln for any other engine. A jacket is one value for every wire, so a design whose wires carry different jackets is refused by name.

Station designs — a build_network() ladder of feedline, tuner arms, and transformers — additionally emit the chain as SimNEC circuit elements in cascade order:

antennaknobs branchSimNEC elementcarried values
TLSERIES_TLINEZo, VFnom, length (ft), k1/k2 matched-loss coefficients (dB/100 ft = k1·√f + k2·f — the same cable-table convention both sides), loss model pinned to k0k1k2
TwoPort L/C armSERIES_IND / SERIES_CAPH / F, component Q quoted at the export frequency
Shunt L/C legSHUNT_IND / SHUNT_CAPH / F, Q likewise
ideal TransformerTRANSFORMER2 (Mdl ideal)turns ratio (SimNEC’s N is the antenna:generator voltage ratio — handled internally, validated live)
Load off the fed segment (traps)SimNEC’s own NECSource load on the $GW_<tag> wire, at the load’s segment centreR/L/C, a fixed z, series or parallel
Load on the fed segmentSERIES_IND / SERIES_CAP between the antenna and the generator (SimNEC turns the EX card into its own source there, so the load has to be a series circuit element instead)H / F
self-tuning l_network_tuner(tune_to=…), "low" / "high"XMATCH (the LC matching component, mode auto)pass, R = the target (X 0), Qc / Ql, MHz = the tune frequency

A self-tuning tuner exports as SimNEC’s own element, not as numbers: SimNEC tunes it against its antenna solve, as antennaknobs tunes it against its own, and importing the file gives the same tuner back. What that element cannot say is refused by name: a T network, "ll" / "cc" parts, component ranges, and a tuner with a fixed shunt side that found no match (SimNEC’s automatic element picks its side, and would). For those, --freeze-tuners (freeze_tuners=True) tunes the box first and writes the parts it chose as ordinary SERIES_* / SHUNT_* elements, which import back as fixed values.

SimNEC’s cascade elements are purely differential: there is no common-mode knob on its transmission line. A design whose physics lives in the common mode — a BalancedLine with zcomm, a FloatingBalun, the balanced tuners built from them — cannot be faithfully represented, and the exporter raises a clear error naming the offending branch instead of silently dropping the common mode and emitting a confidently-wrong circuit. The same applies to non-ladder topologies, current sources, lossy transformers, and distributed (finite-gap) feed ports. A finite-Q Load is refused by name too: SimNEC’s series elements take a fixed R/L/C, not a Q that would need re-deriving per frequency. And a Load that lands on the fed segment can only leave as a series L and/or C (the row above) — a resistor, a fixed z, or a parallel pair there is refused by name, since SimNEC’s own source already owns that spot. About four in five catalog designs export; the refusals tell you exactly what construct is in the way.

Component Q deserves one note: antennaknobs models ql/qc as frequency-independent while SimNEC quotes Q at a frequency, so a lossy component is exact at the export frequency and Q-model-approximate across a SimNEC-side sweep. Q = 0 means ideal (lossless) on both sides.

The reverse direction loads a SimNEC circuit — one you built in SimNEC, or one that came back modified from a round-trip — as antenna geometry plus, for station files, the matching chain as a real build_network(). A re-imported .ssn is a file deck like a .nec: its segment counts are what the file says, so export → import → export is a fixed point — the export’s one-time re-mesh of a fed wire, which puts the feed exactly at its stated position, does not repeat on every hop.

Terminal window
# Any subcommand takes an @file.ssn spec, like @file.nec
python -m antennaknobs draw --builder @station.ssn
python -m antennaknobs sweep --builder @station.ssn --swr
python -m antennaknobs compare_patterns --builders dipoles.invvee @station.ssn
# .ssn -> NEC deck conversion falls out of the pair
python -m antennaknobs export --builder @dip.ssn --out dip.nec

What the importer honours: the solve frequency comes from the Generator’s MHz (in SimNEC the deck’s FR card is advisory), the Generator’s own sweep expression is read (14 : 14.35 : 0.025, lin or log spacing honoured) and becomes the design’s measurement band, the daemon ground call surfaces as a --ground hint (PerfectGround, SommerfeldGround, and MiniNECGround as the MININEC-type ground), and wire conductivity applies to every wire alike, one value for the circuit. NECUnits is read but not applied: in SimNEC it only sets the units wire dimensions are displayed in, and the NEC cards are metres whatever it says. NECOptions.fieldStep (SimNEC’s far-field display step, in degrees) is likewise read and accepted quietly rather than reported as skipped — it is a display resolution, and no solved number depends on it — though a malformed value still refuses. Values are read the way SimNEC writes them: component values with its SI suffixes (37.52p, 731.9n, 2K; its g is a wire gauge and is not a multiplier), and a wire material by name (NECOptions.mhosPerMeter = Conductivities.aluminum;, with SimNEC’s own values). An automatic XMATCH imports as a self-tuning l_network_tuner, which tunes for the solving engine’s own antenna impedance; SimNEC’s MHz 0 (retune at every frequency) tunes once, at the Generator’s frequency, and the import note says so.

A $GW_<tag>.JamSegments(N) is honoured exactly: the file’s N replaces that wire’s GW count and pins it there, so no engine’s even-count rule moves it. An attachment that JamSegments leaves off a segment site — a feed at the middle of an odd-count wire, say — is fed exactly where it is by splitting the wire at that point, never snapped to a neighbouring site. JamSegments(0) means “auto-segment as usual”, so the GW count stands, unpinned. Short of that, SimNEC still re-meshes every wire by its own rules before it solves, so its numbers differ from an import’s by the mesh alone; for a same-mesh comparison, import lastConstructedNEC.nec from ~/.SimNEC/<version>/ instead — the deck SimNEC actually solved.

Each SimNEC block is its own measurement plane: the Generator is "rig" (the far end of the feed system, not the antenna), the deck’s fed wire is "feed" (the antenna’s own terminals) — the same two names EZNEC’s virtual-wire idiom uses in the NEC importer — and every chain block in between gets a node of its own, named after its label, so every block SimNEC reports an impedance at is a measurement plane here too.

Chain elements translate back branch-for-branch through the same table as export, plus one import-only case: a SERIES_Z — SimNEC’s fixed complex impedance — becomes a frequency-independent 2-port Admittance. A SERIES_TLINE’s Mdl simplified loss model (SimNEC’s default: one dB/100-length figure at one frequency) is read and kept as the matched-loss coefficient it implies, exact at that frequency; any other line model is refused by name rather than approximated. A chain element outside the translated set makes network() refuse rather than build a station with a silently-missing tuner part.

Which .ssn files import. SimNEC lets a circuit hold its antenna two ways, and antennaknobs reads one of them: NEC cards between a NEC2 line and a NECEND line, inside a NETWORK element’s script. That is what SimNEC’s NEC portal accepts and what the export above writes, so every round-tripped file qualifies.

The other way is a scriptNECWire and NECSource calls against declared variables, which SimNEC evaluates itself, leaving no cards in the saved file. antennaknobs does not evaluate SimNEC’s scripting language, and says so by name rather than reporting a missing block. To bring such an antenna in, either write its cards into a NEC2 … NECEND block in the NETWORK script, or export a design from antennaknobs to .ssn and edit that.

In Python the same machinery is read_ssn(self, "circuit.ssn") / parse_ssn(text)read_ssn ships a .ssn next to a user design in ~/.antennaknobs/designs/, with the same folder confinement as read_nec.

Export → import is pinned by identity tests: a transformer’s turns ratio and every element value of the validated ladder-tuner cascade (line Zo/VF/length, loss coefficients, both capacitors, coil and its Q) survive the full cycle unchanged. If the two sides ever disagree about a convention, the suite fails rather than the circuits quietly diverging.

momwire is the solver SimNEC calls — pip install momwire provides the momwire-nec2c drop-in engine, and the portal lives in momwire itself. Install, wrapper-script recipe, --basis selection, the probe/version contract, and the dialect it serves are documented on momwire’s own site:

The .ssn export/import above is antennaknobs’ side of the pairing: build or import the antenna here, hand SimNEC the circuit, and point SimNEC’s engine at momwire.

SimNEC is proprietary freeware. antennaknobs emits and parses its open file format for interoperability — like emitting a NEC deck or a Touchstone file — and copies none of SimNEC’s bundled assets. The engine portal (now part of momwire) is the same kind of interoperability in the other direction: it reproduces the printout layout SimNEC’s reader expects, worked out from observed output, and contains no nec2c code.