OpenHFTA is a preservation-oriented Python CLI tool for computing elevation patterns of HF antennas over terrain profiles using the Uniform Theory of Diffraction (UTD) and Fresnel reflection modeling. It provides a modern interface to the OpenYTWCore Fortran numerical engine while aiming to reproduce the behavior of the original HFTA program as closely as possible on modern systems.
This project is dedicated to Richard Dean Straw, N6BV, author of HFTA and a major contributor to amateur radio antenna and propagation work. Dean served on the ARRL staff for 15 years, retired as Senior Assistant Technical Editor in 2008, edited multiple editions of The ARRL Antenna Book, and wrote tools including HFTA, TLW, and Yagi for Windows. ARRL's remembrance notes that Dean died on July 9, 2025, after an extended battle with Parkinson's disease: Richard Dean Straw, N6BV, ARRL "Antenna Expert," Silent Key. ARRL also continues to list HFTA among the supplemental software for The ARRL Antenna Book, while noting that HFTA, TLW, and YW were developed for 32-bit Windows and that there are no plans to update them: ARRL Antenna Book Reference.
OpenHFTA exists to preserve the practical behavior of HFTA for present-day users and systems. Its primary goal is not to replace Dean's work with a new terrain-analysis model, but to make a close, inspectable, and maintainable reimplementation available for study, validation, and continued use.
- Terrain Analysis: Compute antenna elevation patterns over complex terrain profiles
- Diffraction Modeling: UTD-based diffraction analysis (enabled by default, can be disabled with
--no-diffraction) - Fresnel Reflection: Accurate ground reflection calculations with complex soil parameters
- Multi-Element Support: Analyze antenna arrays with customizable heights, phases, and patterns
- Antenna Types: Dipole, 2-Ele, 3-Ele, 4-Ele, 5-Ele, 6-Ele, 8-Ele (no 7-Ele; 8-Ele maps to core type 7)
- Phase Control: Simple asterisk notation (e.g.,
10*) for 180° out-of-phase elements - Move Tower: Shift antenna position relative to terrain profile
- Multiple Profile Comparison: Analyze and compare multiple terrain files simultaneously
- Dual Plot Modes: Terrain profile visualization or elevation pattern analysis
- Angle of Arrival (AoA): Support for AoA probability data and Figure of Merit computation
- Flexible Units: Support for both metric and imperial units for CLI inputs
- Professional Graphics: Publication-quality plots with multiple output formats (PNG, SVG, PDF)
- HFTA Compatibility Focus: Implements the major behavior of the original HFTA GUI with compatibility as the guiding constraint
OpenHFTA treats the original HFTA output as the compatibility target. Pull requests that intentionally improve or modernize the numerical engine in ways that break compatibility with original HFTA behavior will not be accepted here, even when the change is technically defensible as a better model. Users who want to explore a new terrain-analysis engine are encouraged to fork the project and experiment there.
Compatibility-preserving contributions are welcome. In particular, pull requests improving documentation, tests, code comments, variable names, or the accuracy of existing explanations are encouraged. Numerical changes should be framed as compatibility fixes and, where possible, backed by comparisons against the original HFTA behavior.
-
Install Python dependencies:
On Debian or Ubuntu:
sudo apt install python3-numpy python3-matplotlib
On Arch Linux:
sudo pacman -S python-numpy python-matplotlib
-
Build and install OpenHFTA:
make && sudo make install -
Run the tool:
hfta --help
-
Uninstall (if needed):
sudo make uninstall
-
Build the Fortran core:
make
-
Run the tool from the working tree:
./hfta.py --help
Use nix shell to get a shell with openhfta available:
nix shell github:riodxgroup/openhfta
hfta --help
You may use a nix develop shell to do local development, for example:
nix develop -c $SHELL
make
./hfta.py --helpThe examples below assume hfta is installed or available in the active shell.
For local development from the working tree, use ./hfta.py in place of
hfta.
# Analyze 20m antenna pattern over terrain
hfta --profile terrain.pro --freq 14.2
# Disable diffraction analysis
hfta --profile terrain.pro --freq 14.2 --no-diffraction# Two-element stack at 20m and 40m heights
hfta --profile terrain.pro --freq 14.2 \
--heights 20 40 --antenna-type 2-Ele
# Phased array with 180° phase difference using asterisk notation
hfta --profile terrain.pro --freq 14.2 \
--heights 15 '30*' --antenna-type 2-Ele# Custom soil parameters
hfta --profile terrain.pro --freq 14.2 \
--soil-epsr 15.0 --soil-sigma 0.01
# Use predefined soil types (see Common Soil Parameters section)
hfta --profile terrain.pro --freq 14.2 \
--soil-epsr 13.0 --soil-sigma 0.002 # Poor soil# Move tower back 100 meters from current position
hfta --profile terrain.pro --freq 14.2 \
--move-tower 100# Compare two terrain profiles with different antenna types
hfta --profile terrain1.pro --antenna-type 2-Ele --heights 10 20 \
--profile terrain2.pro --antenna-type Dipole --heights 15 \
--freq 14.2
# Advanced comparison with phase notation and tower movement
hfta --profile profile1.pro --antenna-type 3-Ele --heights 10 '15*' 20 --move-tower 50 \
--profile profile2.pro --antenna-type Dipole --heights 12 \
--freq 14.2
# Terrain profile comparison (no elevation analysis)
hfta --profile terrain1.pro --profile terrain2.pro --plot-mode terrainMultiple Profile Syntax: Each terrain file is specified with its own --profile option followed by its specific antenna configuration options (--antenna-type, --heights, --move-tower) before the next --profile option.
Profile-Specific Options (apply to the preceding --profile):
--antenna-type: Dipole, 2-Ele, 3-Ele, ..., 8-Ele (default: Dipole)--heights: Space-separated heights with optional*for out-of-phase (e.g.,10 '15*' 20)--move-tower: Distance to move tower back (default: 0)
# Plot terrain profile instead of elevation pattern
hfta --profile terrain.pro --plot-mode terrain
# Save plot to file (supports svg, pdf, png formats)
hfta --profile terrain.pro --freq 14.2 --output pattern.pdf# Multi-band AoA data (ARRL format, band auto-detected from frequency)
hfta --profile terrain.pro --freq 14.2 \
--aoa 3Y-EU.PRNThe following table lists common soil conductivity and dielectric constant values as used in the original HFTA GUI. These values can be used with the --soil-sigma and --soil-epsr options:
| Soil Type | Conductivity (S/m) | Dielectric Constant | Usage |
|---|---|---|---|
| Very Poor Soil | 0.001 | 5 | --soil-sigma 0.001 --soil-epsr 5 |
| Sandy, Dry Soil | 0.002 | 10 | --soil-sigma 0.002 --soil-epsr 10 |
| Poor Soil | 0.002 | 13 | --soil-sigma 0.002 --soil-epsr 13 |
| Average Soil | 0.005 | 13 | --soil-sigma 0.005 --soil-epsr 13 (default) |
| Good Soil | 0.010 | 14 | --soil-sigma 0.010 --soil-epsr 14 |
| Very Good Soil | 0.030 | 20 | --soil-sigma 0.030 --soil-epsr 20 |
| Fresh Water | 0.001 | 81 | --soil-sigma 0.001 --soil-epsr 81 |
| Salt Water | 5.000 | 80 | --soil-sigma 5.000 --soil-epsr 80 |
Note: The original HFTA GUI displayed conductivity values in mS/m, but the Fortran core expects values in S/m. The values in the table above are already converted to S/m for direct use with this CLI tool.
Terrain profile files contain distance and height pairs:
meters
0 187.1
30 187.8
60 191.2
90 195.0
...
The first line specifies units (meters or feet). Distances and heights are in the specified units. The Python interface automatically converts all terrain data to feet as required by the Fortran core.
Important: The units specified in terrain profile files are independent of the --units CLI option. The terrain file units control how the profile data is interpreted, while the --units option only affects CLI-provided antenna heights and move-tower distances.
Multi-column files containing Angle of Arrival probability data (in percentage) for various bands:
# Example AoA file (ARRL format)
Elev 80m 40m 30m 20m 17m 15m 12m 10m
1 9.1 8.7 10.8 9.9 5.3 6.5 11.1 10.5
2 5.3 4.0 6.4 8.9 7.4 7.3 7.8 11.5
3 1.1 2.9 4.0 7.5 9.0 9.6 9.0 9.3
- Default behavior: Diffraction enabled (more accurate for HF frequencies)
- To disable: Use
--no-diffractionflag - ABI details: The Fortran core expects
DiffractionDisablewhere 1=disable, 0=enable
OpenHFTA uses the OpenYTWCore Fortran implementation accessed via ctypes:
- Symbol:
ytwcore1_(note the trailing underscore) - ABI: All scalar parameters passed by reference (POINTER types in ctypes)
- Arrays: Passed as pointers to contiguous memory
- Units: Terrain profile automatically converted to feet for Fortran core, antenna heights converted to feet internally, angles in degrees
The elevation pattern is computed at 140 angle samples from 0.25° to 35.0° in 0.25° steps, matching the original HFTA specification.
For detailed information about the theoretical foundations:
- docs/THEORY.md: Comprehensive overview of UTD theory, Fresnel reflection, terrain modeling, and the mathematical foundations underlying the elevation pattern calculations
- docs/PORTING_NOTES.md: Technical details about the Fortran core implementation, numerical sensitivity, and compiler considerations
See the test/pro/ directory for sample terrain profiles that can be used for testing and validation.
If you get "Cannot find OpenYTWCore library":
# Build the shared library first
make
# Or specify explicit path
./hfta.py --lib ./libopenytwcore.so --profile terrain.pro --freq 14.2Install required packages from your distribution, for example:
sudo apt install python3-numpy python3-matplotlibIf you get "Symbol ytwcore1_ not found", ensure you're using the correct Fortran library built from this repository. The symbol name includes the trailing underscore as per gfortran conventions.
The original HFTA DLLs are not distributed with this repository. Differential
tests against the legacy implementation are enabled only when YTWCore.dll and
DFORRT.DLL are present in test/; those files are ignored by git. Without
them, make test-core skips the legacy comparison but the rest of the test
suite still runs.