fnec-rust is a Rust-native antenna modeling workspace targeting near-100% practical compatibility with 4nec2, while keeping the codebase modular, testable, and portable.
- Parse 4nec2 / NEC2 deck files (GW, GM, GR, GE, GN, EX, FR, RP, EN cards)
- GM (Geometry Move): rotate and/or translate wire ranges in place, or append one transformed copy when
tag_increment > 0 - GR (Geometry Repeat): supported subset repeats existing wires by successive z-axis rotation
- EX type 1: staged portability support is accepted in the parser/solver path and currently runs with EX type 0 behavior plus an explicit warning while current-source semantics remain pending
- EX type 2: staged portability support is accepted in the parser/solver path and currently runs with EX type 0 behavior plus an explicit warning while incident-plane-wave semantics remain pending
- EX type 4: staged portability support is accepted in the parser/solver path and currently runs with EX type 0 behavior plus an explicit warning while segment-current semantics remain pending
- EX type 5: staged portability support is accepted in the parser/solver path and currently runs with EX type 0 behavior plus an explicit warning while qdsrc semantics remain pending
- PT: staged portability parsing is supported; current runtime emits an explicit deferred-support warning and ignores PT electrical semantics
- NT: staged portability parsing is supported; current runtime emits an explicit deferred-support warning and ignores NT electrical semantics
- GM (Geometry Move): rotate and/or translate wire ranges in place, or append one transformed copy when
- Hallén MoM solver — physically accurate feedpoint impedance for thin-wire antennas
- Validated: 51-segment λ/2 dipole at 14.2 MHz → 74.24 + j13.90 Ω (matches Python reference)
- GN 1 (perfect ground at z=0) is supported via image method;
dipole-ground-51segregression is 81.91 + j16.42 Ω - GN 0 (simple finite-ground reflection coefficient path) is supported;
dipole-gn0-fresnel-51segis regression-gated - GN 2 low above-ground finite-conductivity cases are supported on the current scoped path; the supported subset is strictly above-ground (
z > 0);dipole-gn2-deferredanddipole-gn2-near-ground-51segare regression-gated - Buried or interface-touching active-ground wire classes (
z <= 0) remain deferred and fail fast with an actionable error instead of silently falling back - GN types outside the current scoped subset still remain deferred
- GE ground-reflection flag:
1= PEC image (handled);-1= below-ground (warns); other values warn with valid range hint - Multi-wire junctioned / non-collinear Hallen (unique to fnec-rust): per-wire local cos(k·s) homogeneous vectors, KCL junction continuity rows, and correct passive-wire (zero) RHS — no other NEC2-compatible tool handles junctioned wire topologies via the Hallen integral equation; validated against NEC2 on
dipole-loadedtop-hat geometry (Z ≈ 12.4−j918 Ω, NEC2 ref 13.5−j896 Ω); external cross-check recommended for novel geometries
- GN 1 (perfect ground at z=0) is supported via image method;
- Validated: 51-segment λ/2 dipole at 14.2 MHz → 74.24 + j13.90 Ω (matches Python reference)
- Segment current distribution table in CLI output (
CURRENTSsection after feedpoint table) - RP radiation-pattern execution in CLI output (
RADIATION_PATTERNsection with theta/phi gain rows) - Corpus validation can track and optionally gate external parity candidates (RP and impedance) recorded in
corpus/reference-results.json - Pulse-basis and continuity-basis Pocklington solvers (EXPERIMENTAL — known to diverge for thin wires)
- Sinusoidal-basis Hallen solve path with guarded residual fallback to Hallen
sinusoidalfalls back to Hallen on single collinear chains when its residual budget is exceeded, and the budget is user-tunable via--sin-fallback-rel-max(orFNEC_SIN_FALLBACK_REL_MAX)
- CLI binary
fnecwith selectable solver and RHS modes - FR sweep support in CLI output and corpus validation gating
- Residual diagnostics printed to stderr on every run
- Modular crate workspace: parser, model, solver, accel, report, project, CLI, GUI
cargo build --release
./target/release/fnec dipole.nec
Example deck (dipole.nec):
GW 1 51 0 0 -5.282 0 0 5.282 0.001
GE
EX 0 1 26 0 1.0 0.0
FR 0 1 0 0 14.2 0.0
EN
Example output (report contract v1):
FNEC FEEDPOINT REPORT
FORMAT_VERSION 1
FREQ_MHZ 14.200000
SOLVER_MODE hallen
PULSE_RHS Nec2
FEEDPOINTS
TAG SEG V_RE V_IM I_RE I_IM Z_RE Z_IM
1 26 1.000000 0.000000 0.013013 -0.002436 74.242874 13.899516
See docs/cli-guide.md for full option reference and docs/card-support-matrix.md for the NEC card support matrix.
If this project helps your work, please consider supporting ongoing development:
https://www.paypal.com/donate/?hosted_button_id=WY9U4MQ3ZAQWC
- Primary compatibility target: 4nec2 input and workflow expectations
- Secondary input dialect support: xnec2c where it provides real benefit
- Solver implemented from scratch in Rust
- CLI and GUI frontends over a shared core
- Multithreaded CPU execution with staged GPU acceleration
- Explicit Linux-on-ARM targets: Raspberry Pi 4 (VideoCore VI GPU) and Raspberry Pi 5 (VideoCore VII GPU)
crates/
nec_parser/
nec_model/
nec_solver/
nec_accel/
nec_report/
nec_project/
apps/
nec-cli/
nec-gui/
docs/
Install the required cargo tools:
cargo install cargo-audit cargo-sbom cargo-fuzzInstall the local git hooks:
make install-hooksThis configures core.hooksPath to use .githooks/.
- Pre-commit:
cargo fmt --all -- --check,cargo test --workspace - Pre-push:
cargo audit - Docs validation:
./scripts/validate-doc-frontmatter.sh - Parser fuzz scaffold:
(cd fuzz && cargo fuzz run nec_parser_parse corpus/nec_parser_parse) - Remote ARM64 check (Pi over SSH):
bash ./scripts/pi-remote-workspace-check.sh <user@host> - Remote ARM64 benchmark CSV (Pi over SSH):
bash ./scripts/pi-remote-benchmark.sh <user@host> - Remote benchmark with explicit single-thread baseline + parallel CPU sweep:
FNEC_BENCH_EXECS="cpu-single cpu" bash ./scripts/pi-remote-benchmark.sh <user@host> - Remote benchmark with persistent history append:
FNEC_BENCH_HISTORY="benchmarks/pi-benchmark-history.csv" bash ./scripts/pi-remote-benchmark.sh <user@host> - Benchmark CSV delta view:
bash ./scripts/pi-benchmark-compare.sh <base.csv> <candidate.csv> - Benchmark CSV delta gate example:
bash ./scripts/pi-benchmark-compare.sh --max-delta-pct 15 --fail-on-mode-drift <base.csv> <candidate.csv> - Append benchmark CSV to persistent history:
bash ./scripts/pi-benchmark-history.sh append <candidate.csv> benchmarks/pi-benchmark-history.csv - Benchmark history trend summary:
bash ./scripts/pi-benchmark-history.sh trend benchmarks/pi-benchmark-history.csv
GitHub Actions includes benchmark-compare.yml, which runs on PRs and compares benchmarks/pi-base.csv vs benchmarks/pi-candidate.csv when both files exist. If either file is missing, the job reports a clean skip.
When it runs, it also writes a benchmark delta preview to the Actions job summary.
If you review or approve workflow/tool actions from a mobile device, some approval dialogs may be truncated, fail to render all options, or not submit reliably.
- Prefer desktop browser approval for multi-step actions (branch push, workflow changes, multi-file edits).
- If a mobile approval appears stuck, refresh and retry from desktop rather than re-running commands repeatedly.
- Keep command payloads and commit messages concise when you know approvals may be handled on mobile.
When bumping the workspace version:
- Update
Cargo.toml. - Regenerate the SPDX SBOM:
cargo sbom --output-format spdx-json > SBOM.spdx.json - Update
docs/changelog.md. - Update
docs/releasenotes.md. - Update documentation references that include the new version.
main stays protected. Work happens on feature branches only, followed by pull requests.