Find the wire length (and counterpoise length) that gives the lowest VSWR across every ham band you care about — backed by real NEC-2 method-of-moments simulation, not guesswork.
Author: LU3VEA · License: CC0 1.0 (public domain, script and documentation only — see Third-party licensing note) · Platform: Windows installer, Linux AppImage, or cross‑platform Python script
If you're building a multi-band wire antenna, the eternal question is: how long should the wire be? This tool answers that question empirically instead of by rule of thumb.
It models three topologies, selected with --antenna-type:
long-wire(default) — an end-fed or sloping radiator with an optional counterpoise, ground rod or coax stub as the RF return path. Matched with an UnUn.ocfd— an off-centre-fed dipole (Windom): both arms radiate, the dipole is its own return path, and--wire-len/--cp-lenbecome the long and short arms. Matched with a balun.carolina-windom— an OCFD with an extra radiating vertical section between the balun and a line isolator.
It sweeps a grid of candidate radiator lengths and counterpoise lengths (the counterpoise is the secondary wire or ground reference that provides the RF return path for an end-fed antenna — see Glossary), and for every combination:
- Generates a NEC-2
.necinput deck (sloping radiator + sloping counterpoise, with ground and wire-material modeling). - Runs
nec2cto simulate the antenna at the center frequency of each of your target bands. - Parses the impedance results and computes an aggregate VSWR score across all active bands, with penalties for bands that miss your target take-off angle or gain.
- Tracks the Pareto-optimal candidates (best trade-offs between the bands, rather than a single band winning at the expense of the others).
At the end you get a ranked report, a scatter plot of the whole search space, a CSV of the best candidates, a ready-to-simulate .nec file for the winner, radiation-pattern diagrams, a construction diagram, and an optional one-page PDF "antenna brochure" summarizing the build.
It can also recommend the best standard UnUn transformation ratio (e.g. 9:1, 4:1, 1:1 — an UnUn is an "unbalanced-to-unbalanced" impedance-transforming feedline matching transformer; see Glossary) for your feedline, and warn you when no ratio removes the impedance mismatch cleanly enough on a given band.
- 📐 Three antenna topologies — end-fed long wire (default), off-centre-fed dipole (Windom), and Carolina Windom, each with its own matching device, empirical fallback model and geometry-quality metric (
--antenna-type). - 🎯 Multi-band optimization — optimize for any combination of bands simultaneously (e.g.
40m,20m,17m,15m,10m), not just one. - 📡 Real NEC-2 physics — uses method-of-moments simulation (
nec2c) rather than closed-form approximations, including realistic ground models (Sommerfeld/Norton or perfect ground). - ⚡ Fast empirical mode — an
--mode empiricalfallback using closed-form formulas when you don't havenec2cinstalled or just want a quick estimate;--mode autopicks the best available. - 🌍 Multilingual CLI — full English, Spanish, and Italian interfaces, auto-detected from your system locale (or force with
--lang). - 🖥️ GUI mode — a Tkinter front-end (
--gui) for anyone who'd rather not touch a terminal. - 🔧 Physically realistic modeling — configurable wire diameter and material (copper, aluminium, brass, silver, steel, or lossless "perfect"), sloped or horizontal wire geometry, real-world height and ground parameters.
- 🔌 UnUn ratio advisor — evaluates standard transformation ratios against the raw antenna impedance and tells you which one gets you closest to a clean match on every band.
- 🧰 Matching-network designers built in — the GUI's UnUn/Transmatch tab loads the winning antenna's per-band impedances automatically and designs either a wideband UnUn autotransformer (on a ferrite/iron-powder toroid from a 16-core database, or as an air-core solenoid) or a tapped-coil Transmatch, complete with turns, tap positions, wire lengths, core-heating estimates and a construction drawing you can save as a PNG.
- ⚙️ Parallel and refinement modes —
--fast-runsolves independentnec2cdecks concurrently (--jobs Nto set the worker count), and--test-windowturns each retry into a finer sweep of the best region instead of a wider one. - 📊 Rich output — ranked text report, scatter plot (PNG), CSV of top candidates, best-candidate
.necdeck, radiation-pattern diagrams, construction diagram, and a PDF brochure. - 🪟 One-click Windows installer — bundles Python,
nec2c, and all dependencies so non-technical hams can get running without touching a package manager. - 🐧 One-click Linux AppImage — same idea for Linux, no
pip installor package manager required.
There is currently no packaged installer for macOS. macOS users should use Option C below.
| File / folder | Description |
|---|---|
src/Long_Wire_Antenna.py |
The optimizer itself — a self-contained Python script (CLI + optional GUI). This is the file you run directly for Option C. |
Setup_Long_Wire_Antenna.exe |
Prebuilt, self-contained Windows installer (embeds Long_Wire_Antenna.py, nec2c.exe, the launcher, and the post-install script — nothing else needs to sit alongside it). |
Long_Wire_Antenna-x86_64.AppImage |
Prebuilt Linux AppImage — the one-click equivalent of the Windows installer for x86_64 Linux. |
documentation/Long_Wire_Antenna_Manual_EN.md |
Extended English user manual. |
documentation/Long_Wire_Antenna_Manual_ES.md |
Extended Spanish user manual. |
documentation/Long_Wire_Antenna_Manual_IT.md |
Extended Italian user manual. |
README_es.md, README_it.md |
Spanish and Italian translations of this README. |
images/logo.png, images/icon.png |
Project logo (shown at the top of this README) and application icon (used for the Windows installer/shortcuts and the Linux AppImage). |
others/build_windows_installer.sh |
Build script that compiles Setup_Long_Wire_Antenna.exe from the sources in others/windows_installer/ using NSIS (makensis). Run on Fedora/RHEL or Debian/Ubuntu; installs nsis and imagemagick automatically if missing. |
others/windows_installer/long_wire_antenna_installer.nsi |
NSIS script that defines the Windows installer, built by build_windows_installer.sh above. |
others/windows_installer/nec2c.exe |
Prebuilt Windows binary of the NEC-2 method-of-moments engine that gets embedded into Setup_Long_Wire_Antenna.exe. Third-party binary — see licensing note. Not meant to be used standalone — see Option C if you need a nec2c binary for a manual/non-Windows setup. |
others/windows_installer/payload/run_gui.bat |
Launcher batch file installed alongside the script; this is what the Desktop shortcut actually runs. It sets UTF-8 console/Python encoding, points the NEC2C environment variable at the bundled engine, and then runs Long_Wire_Antenna.py --gui. |
others/windows_installer/payload/post_install_setup.py |
Runs once, automatically, at the end of installation (using the just-installed Python interpreter) to pip install the required packages and finish setting up the NEC2 engine. See the Windows installer note below. |
others/build_appimage.sh |
Build script that produces the portable, self-contained Linux AppImage (bundled Python + Tk + statically-built nec2c, no host dependencies). |
LICENSE |
CC0 1.0 Universal (public domain dedication) — applies to this project's own script and documentation, not to bundled third-party binaries. |
⚠️ Note on file paths: the table above describes the reorganised layout (src/,documentation/,others/). Until that reorganisation lands onmain, the published repository still uses flat, legacy names —nec2_length_optimizer.py,NEC2_Length_Optimizer_Manual_EN.md,README.es.md/README.it.md,NEC2_Length_Optimizer_Setup.exe,nec2-optimizer-x86_64.AppImage,nec2_optimizer_installer.nsi,build_appimage.shandnec2c.exe, all at the repository root. If a path in this document 404s, look for its legacy name at the root, and readpython src/Long_Wire_Antenna.pyin every command example aspython nec2_length_optimizer.py.
Note on binary files in this repository: the Windows installer (
Setup_Long_Wire_Antenna.exe), the installer's bundlednec2c.exe, and the Linux AppImage (Long_Wire_Antenna-x86_64.AppImage) are committed directly to this git repository rather than published as separate GitHub Releases. This is convenient for direct download but means the repository history includes binary blobs. No SHA-256 checksums are currently published for these files in this README; if you need to verify integrity, compute the hash yourself after download (sha256sum <file>on Linux/macOS,certutil -hashfile <file> SHA256on Windows) and compare against a checksum obtained from a trusted channel, since none is published here yet.
Download and run Setup_Long_Wire_Antenna.exe. It's fully self-contained — no other files need to sit alongside it. It will:
- Check for a Python 3 interpreter and silently install Python 3.12.7 (64-bit) from python.org if missing (with pip, the
pylauncher, and PATH configured). - Install
Long_Wire_Antenna.py, therun_gui.batlauncher,post_install_setup.py, the app icon, and the license text into the target install directory (C:\Program Files\LongWireAntennaby default). - Install the bundled
nec2c.exeinto%INSTDIR%\nec2c\, and also mirror a copy toC:\Program Files\OpenNEC\andC:\Program Files (x86)\OpenNEC\. - Run
post_install_setup.py, whichpip installs the Python packages (numpy,matplotlib,tabulate,colorama,reportlab) and then double-checks the NEC2 engine — see the note below. - Create a Desktop shortcut that runs
run_gui.bat, which in turn launchesLong_Wire_Antenna.py --gui. - Register a standard Windows uninstaller.
⚠️ Extra dependency note: step 4 alsopip installs a fifth package,tabulate, alongside the four the script actually needs.Long_Wire_Antenna.pydoes not import or usetabulateanywhere — it is unused leftover in the installer's dependency list, not a real requirement. It costs nothing except a few extra seconds of install time and disk space, and you don't need it if you're setting the script up manually (Option C).
⚠️ Known installer quirk (engine self-upgrade step): as part of step 4,post_install_setup.pyoptionally tries to download a newer NEC2 engine build from an external GitHub project and, if it finds one, verifies it starts correctly before using it — falling back to "the bundled engine" if the download fails or the downloaded build doesn't run. However, its fallback logic looks for a bundled file namedonec.exe/onec_bundled.exe, while the installer only ever ships a file namednec2c.exe. In practice this just means the optional online-upgrade step can't find that baseline file to fall back to, so it's a no-op unless the network download succeeds. It does not break a normal install:run_gui.batindependently looks for (and finds)nec2c\nec2c.exeand points theNEC2Cenvironment variable at it directly, so the bundled engine is used correctly either way. Worth knowing if you're troubleshooting install logs that mentiononec.exe.
⚠️ Known bug (Windows, only if you bypassrun_gui.bat): step 3 mirrors the engine toC:\Program Files\OpenNEC\nec2c.exeandC:\Program Files (x86)\OpenNEC\nec2c.exe. However,Long_Wire_Antenna.py's own hardcoded Windows fallback search paths look for a file namedonec.exein those same two folders, notnec2c.exe— the filenames don't match, so the script's built-inProgram Files\OpenNECfallback will not find the installer's copy there. This has no effect on the normal Desktop-shortcut flow, becauserun_gui.batsets theNEC2Cenvironment variable directly and never relies on this fallback. It only matters if you open a plain terminal/PowerShell after installing and runpython Long_Wire_Antenna.py(orpy Long_Wire_Antenna.py) yourself, withoutrun_gui.bat, without%NEC2C%set, and without%INSTDIR%\nec2con yourPATH— in that specific case, NEC2 mode will report "binary not found" even though a working engine is sitting inProgram Files\OpenNEC. Work around it with--nec2c "C:\Program Files\OpenNEC\nec2c.exe", or by settingNEC2Cyourself, or by using the Desktop shortcut /run_gui.batinstead.
Download Long_Wire_Antenna-x86_64.AppImage, make it executable, and run it:
chmod +x Long_Wire_Antenna-x86_64.AppImage
./Long_Wire_Antenna-x86_64.AppImage
The AppImage bundles its own Python 3.11 interpreter (with Tkinter), numpy, matplotlib, colorama, reportlab, pillow, and a statically-linked nec2c binary — nothing else needs to be installed on the host system, and no pip install step is required.
⚠️ The AppImage always launches straight into the GUI, regardless of any command-line arguments you pass it — GUI mode is forced unconditionally. This mirrors how--guibehaves when passed to the raw Python script (see the--guiwarning in Usage below): the GUI opens with its own defaults, and there is currently no way to pre-fill it from the command line. To use the CLI instead, run Option C.
You can rebuild it yourself from source with others/build_appimage.sh (best run on an old base like Ubuntu 20.04, or the official AppImage builder Docker image, to keep the glibc requirement low).
This is also the only supported path for macOS, since there is no packaged macOS installer.
Requirements:
- Python 3.8+
nec2con yourPATH(or point to it with--nec2c) — optional if you only plan to use--mode empirical- Python packages:
pip install numpy matplotlib colorama reportlab pillow
colorama, matplotlib, numpy, reportlab, and pillow are all optional — the script degrades gracefully (no color, no plot/PDF output) if they aren't installed. numpy is only actually needed for the radiation-pattern diagrams and is normally installed automatically as a dependency of matplotlib, so you rarely need to install it by hand. pillow (PIL) is only needed to embed the construction/radiation PNGs into the PDF brochure; without it the PDF is still generated, with an "(unavailable)" placeholder in the affected image section.
NEC2C binary discovery order:
--nec2c /path/to/nec2c(explicit flag)$NEC2Cenvironment variablePATH(nec2c,nec2c-mpich,onec)- Common install paths (
/usr/bin,/usr/local/bin,/opt/nec2c/bin, etc.) - Interactive prompt (unless
--no-interactiveis set)
If nec2c cannot be found through any of these and --no-interactive is set (or you decline the prompt), the script falls back to --mode empirical when --mode auto is in effect, or exits with an error if you explicitly requested --mode nec2.
python src/Long_Wire_Antenna.py --bands 40m,20m,15m --wire-len 21.0 --cp-len 5.0
Center frequencies for known bands are resolved automatically, so --freqs is optional here.
python src/Long_Wire_Antenna.py --bands 40m,20m,15m --freqs 7.1,14.2,21.2 \
--wire-len 21.0 --cp-len 5.0
python src/Long_Wire_Antenna.py --bands 40m,20m,15m --freqs 7.1,14.2,21.2 \
--active-bands 40m,20m --wire-len 21.0 --cp-len 5.0
python src/Long_Wire_Antenna.py --gui
⚠️ --guioverrides everything else. It is checked before the rest of the command line is parsed, so if you combine it with other flags (e.g.python src/Long_Wire_Antenna.py --gui --bands 40m,20m), those other flags are silently ignored — no warning or error is printed, and the GUI simply opens with its own built-in defaults. There is currently no way to pre-populate GUI fields from CLI arguments. Once the GUI is open, use its own fields to set everything.
python src/Long_Wire_Antenna.py --help
Supported band presets span LF through UHF: 2200m, 630m, 160m, 80m, 60m, 40m, 30m, 20m, 17m, 15m, 12m, 10m, 6m, 4m, 2m, 70cm, 23cm.
| Flag | Purpose |
|---|---|
--bands / --freqs |
Bands to model, and their frequencies (MHz) if not in the known-band table. |
--active-bands |
Subset of --bands that actually contributes to the optimization score. |
--wire-len, --cp-len |
Starting/center radiator and counterpoise lengths (m). |
--wire-min/max/step, --cp-min/max/step |
Define the search grid around the starting lengths. |
--mode {empirical,nec2,auto} |
Use closed-form formulas, full NEC-2 simulation, or auto-select. |
--height |
Antenna height above ground (m). |
--wire-slope-end-height, --cp-end-height |
Model a sloping wire/counterpoise by setting the far-end height (0 = end at ground level). |
--no-counterpoise |
Model a counterpoise-less end-fed antenna. In NEC2 mode the RF return path defaults to ground-rod; use --no-cp-return to pick coax-stub instead, or to reject the configuration. |
--no-cp-return {ground-rod,coax-stub,reject} |
How the RF return path is modeled when there's no counterpoise. |
--ground-model {sommerfeld,perfect} |
Ground model used by NEC-2. |
--ground-cond, --ground-diel |
Ground conductivity (S/m) and dielectric constant. |
--wire-diameter, --wire-material |
Physical wire diameter (mm) and material (copper, aluminium/aluminum, brass, silver, steel, perfect). |
--feed-model {straddle,junction} |
Where the NEC-2 source card sits relative to the radiator/counterpoise junction. straddle (default) converges far faster; junction reproduces older results, and is forced for carolina-windom. |
--antenna-type {long-wire,ocfd,carolina-windom} |
Antenna topology. long-wire (default) is the end-fed radiator described above. The dipole types turn --wire-len / --cp-len into the long and short arms of an off-centre-fed dipole, reject --no-counterpoise, and design a balun instead of an UnUn. carolina-windom adds a radiating vertical section and forces --feed-model junction. |
--total-len, --offset, --offset-min/max/step |
Off-centre-fed types: total length of both arms, and the short-arm fraction (default 0.3333, the classic Windom third; valid range 0.10–0.49) — the usual way to specify a Windom. The -min/max/step trio bounds the offset sweep. |
--balun-ratio, --balun-kind, --balun-core, --balun-turns |
Balun design for the dipole types: ratio (auto, or one of 2/4/6/9 — a transmission-line balun exists at those ratios and not in between), topology (guanella current balun by default, or ruthroff), toroid core and turns per line. |
--cw-vert-len, --cw-isolator-z |
Carolina Windom only: length of the radiating vertical section (default 3.0 m), and the line isolator modelled as a finite series impedance (e.g. 1000,2000) instead of an ideal open — useful for studying what an inadequate choke costs you. |
--feed-choke, --match-model {ideal,real} |
Also design a feedline common-mode choke (always designed for carolina-windom, where it is the line isolator); and whether VSWR through the matching device is idealised or includes the balun's finite magnetising reactance. |
--fast-run, --jobs N |
--fast-run is the acceleration policy (coarse sweep, shorter refinement/re-rank lists, one convergence arm) — a cheaper answer. --jobs N runs independent nec2c solves concurrently and is honoured with or without --fast-run: it only shortens the wall clock, never changes a published number. Defaults: 1 (serial), or one per core capped at 16 under --fast-run. Published impedances stay at fine density. |
--retry N, --test-window, --refine-top N |
Re-run the sweep up to N extra times: shifting the window outwards by default, or — with --test-window — refining it around the best --refine-top candidates at half the grid step. |
--converge |
Re-simulate the winner at 0.5× and 2× the working segmentation and report how far R and X still move. NEC2 mode only. |
--target-toa |
Target radiation take-off angle (degrees) used in scoring. |
--gain-weight |
Weight of gain vs. VSWR in the aggregate score. |
--top-n |
Number of ranked candidates to report. |
--out-txt, --out-png, --out-csv, --out-nec, --out-radiation, --out-construction, --out-pdf |
Output file paths for each report artifact. |
--lang {en,es,it} |
Force UI language (auto-detected from locale otherwise). |
--gui |
Launch the Tkinter GUI instead of the CLI. Overrides and silently ignores all other flags — see the warning above. |
--quiet / -q |
Suppress non-essential console output. |
Run --help for the complete, up-to-date list — the script has many more fine-tuning knobs (segments per half-wave, fast/converge modes, retry counts, etc.).
A typical run produces:
optimizer_report.txt— ranked text report of the best candidates and their per-band VSWR.optimizer_plot.png— scatter plot of the entire search space with the Pareto front highlighted.optimizer_best.csv— top candidates in CSV form, ready to import elsewhere.best_antenna.nec— the NEC-2 deck for the winning geometry, ready to re-simulate or tweak.radiation_diagrams.png— radiation pattern plots for the winning antenna.antenna_construction.png— a construction/build diagram.antenna_brochure.pdf— a one-page PDF summary (requiresreportlab).
The GUI's UnUn/Transmatch tab writes a few more files, on demand rather than automatically: unun_toroid.png or unun_solenoid.png (the UnUn construction drawing), transmatch_coil.png (the tapped-coil drawing), and unun_transmatch.txt (an Export of both calculators' results, saved alongside a _transmatch.png copy of the coil drawing).
For each candidate (wire_len, cp_len) pair, the script computes a per-band VSWR from the simulated (or empirically estimated) feedpoint impedance, then aggregates those into a single penalized score that also accounts for:
- Deviation from the desired radiation take-off angle (weighted by
--gain-weight). - How far the counterpoise length is from an "ideal" quarter-wave relationship for each band.
- Non-Pareto-dominated candidates are flagged so you can see genuine multi-band trade-offs rather than a single best number.
The tool then separately checks standard UnUn transformer ratios (1:1, 4:1, 9:1, etc.) against the winning antenna's raw impedance and reports which ratio(s) bring VSWR closest to 1:1 on each band — and flags bands where no standard ratio resolves the mismatch, since forcing a single feedline design to cover many unrelated bands is sometimes physically impossible.
- Counterpoise — a wire (or set of wires) connected to the RF-return/ground side of an end-fed antenna's feedpoint, used instead of (or in addition to) a true earth ground to provide the return path for RF current.
- VSWR (Voltage Standing Wave Ratio) — a measure of how well the antenna's impedance is matched to the feedline; 1:1 is a perfect match, higher numbers mean more reflected power.
- UnUn (Unbalanced-to-Unbalanced transformer) — an RF transformer that changes impedance (e.g. 9:1, 4:1) between an unbalanced feedline (coax) and an unbalanced antenna such as an end-fed wire, used to bring the antenna's raw impedance closer to the feedline's characteristic impedance (typically 50 Ω).
- Take-off angle (TOA) — the vertical angle above the horizon at which an antenna radiates its peak far-field signal; lower angles generally favor long-distance (DX) propagation.
- Pareto-optimal candidate — a candidate
(wire_len, cp_len)pair for which no other candidate is simultaneously at least as good on every active band and strictly better on at least one; i.e. a genuine multi-band trade-off rather than a dominated (strictly worse) option.
| Symptom | Likely cause | What to do |
|---|---|---|
--mode nec2 exits immediately with a "binary not found" style error |
nec2c could not be located by any discovery step, and --mode nec2 does not fall back |
Install nec2c, or pass --nec2c /full/path/to/nec2c, or set the $NEC2C environment variable. With --mode auto instead, the script falls back to --mode empirical automatically rather than exiting. |
On Windows, nec2c/onec.exe is not found even though the installer succeeded, and you did not launch via the Desktop shortcut |
You ran Long_Wire_Antenna.py directly (bypassing run_gui.bat) without %NEC2C% set — see the known bug above about the nec2c.exe/onec.exe filename mismatch under Program Files\OpenNEC |
Use the Desktop shortcut / run_gui.bat, or pass --nec2c "C:\Program Files\OpenNEC\nec2c.exe" explicitly, or set NEC2C yourself. |
| A band is flagged as poorly matched by every standard UnUn ratio | The raw antenna impedance on that band is far enough from every ratio in the built-in sweep (1:1, 1.5:1, 2:1, 3:1, 4:1, 6:1, 9:1, ...) that none of them bring VSWR close to 1:1 | This is expected for some multi-band designs — a single feedline strategy cannot always match unrelated bands equally well. Options: accept the higher VSWR on that band, use the Transmatch (tapped-coil) calculator instead of, or in addition to, the UnUn for that band, or re-run the optimizer with a different/narrower search window or a different --active-bands selection to find a geometry that compromises less on it. |
matplotlib/numpy/reportlab is missing but a plot/PDF was requested |
Optional package not installed | The run still completes and writes the non-graphical outputs (text report, CSV, .nec deck); the script prints which optional output was skipped and why. Install the missing package(s) with pip install matplotlib numpy reportlab (see Option C) and re-run. |
This project's own source code (src/Long_Wire_Antenna.py), build scripts, and documentation are released under CC0 1.0 Universal (public domain) — see LICENSE.
The bundled nec2c.exe (Windows) and the statically-linked nec2c binary inside the Linux AppImage are third-party software — the nec2c C translation of NEC-2 by Neoklis Kyriazis (5B4AZ), itself derived from the original NEC-2 code developed at Lawrence Livermore National Laboratory. These binaries are not covered by this project's CC0 dedication; they retain their own upstream licensing terms.
If you redistribute this project (including the bundled installer, AppImage, or nec2c.exe), make sure your redistribution also complies with nec2c's own license terms, not just this project's CC0 dedication.
This project's own code and documentation are released under CC0 1.0 Universal — public domain. Do whatever you like with it, no attribution required. See LICENSE for the full legal text. Bundled third-party binaries are excluded — see Third-party licensing note above.
- NEC-2 (Numerical Electromagnetics Code) — the underlying antenna simulation engine.
- Built by LU3VEA for the amateur radio community.
73! If this tool helped you build a better antenna, consider sharing your results with the community.
