API Reference¶
This page contains the complete API reference for DVOACAP Python.
Core Modules¶
Path Geometry¶
PathGeom - Path Geometry Module for VOACAP Ported from PathGeom.pas (DVOACAP)
Original Author: Alex Shovkoplyas, VE3NEA Python Port: 2025
This module handles 2D and 3D path geometry calculations for HF propagation: - Great circle path calculations - Azimuth calculations (transmitter to receiver and vice versa) - Point-along-path calculations - 3D hop geometry (elevation angles, hop distances, etc.)
- class dvoacap.path_geometry.GeoPoint(lat: float, lon: float)[source]¶
Bases:
objectGeographic point with latitude and longitude in radians
- dvoacap.path_geometry.clamp_cosine(cos_val: float) float[source]¶
Clamp cosine value to [-1, 1] to avoid numerical errors
- class dvoacap.path_geometry.PathGeometry[source]¶
Bases:
objectHandles great circle path geometry calculations between transmitter and receiver.
This class computes: - Great circle distance - Azimuths (Tx->Rx and Rx->Tx) - Points along the path - Hop counts for given elevation angles
- set_tx_rx(tx: GeoPoint, rx: GeoPoint) None[source]¶
Set transmitter and receiver locations and compute path parameters.
- Parameters:
tx – Transmitter location (GeoPoint with lat/lon in radians)
rx – Receiver location (GeoPoint with lat/lon in radians)
- get_point_at_dist(dist: float) GeoPoint[source]¶
Get a point along the great circle path at a given distance from Tx.
- Parameters:
dist – Distance from transmitter in radians
- Returns:
GeoPoint at the specified distance along the path
- dvoacap.path_geometry.hop_distance(elev: float, height: float) float[source]¶
Calculate the ground distance of one hop in radians.
- Parameters:
elev – Elevation angle in radians
height – Virtual height in km
- Returns:
Hop distance in radians
- dvoacap.path_geometry.hop_length_3d(elev: float, hop_dist: float, virt_height: float) float[source]¶
Calculate the 3D length of a hop path.
- Parameters:
elev – Elevation angle in radians
hop_dist – Hop distance (ground) in radians
virt_height – Virtual reflection height in km
- Returns:
3D hop path length in km
- dvoacap.path_geometry.calc_elevation_angle(hop_dist: float, height: float) float[source]¶
Calculate elevation angle from hop distance and height.
- Parameters:
hop_dist – Hop distance in radians
height – Virtual height in km
- Returns:
Elevation angle in radians
- dvoacap.path_geometry.sin_of_incidence(elev: float, height: float) float[source]¶
Calculate sine of incidence angle at ionosphere.
- Parameters:
elev – Elevation angle in radians
height – Height in km
- Returns:
Sin of incidence angle
Solar Calculations¶
Solar Calculations Module for VOACAP Ported from Sun.pas (DVOACAP)
Original Author: Alex Shovkoplyas, VE3NEA Python Port: 2025
This module calculates solar position and local time for HF propagation modeling.
- class dvoacap.solar.GeographicPoint(latitude: float, longitude: float)[source]¶
Bases:
objectGeographic location in radians
- classmethod from_degrees(lat_deg: float, lon_deg: float) GeographicPoint[source]¶
Create point from degrees
- dvoacap.solar.compute_zenith_angle(point: GeographicPoint, utc_fraction: float, month: int) float[source]¶
Calculate solar zenith angle at a geographic point.
The zenith angle is the angle between the sun and the local vertical. It’s used to determine day/night terminator and ionospheric conditions.
- Parameters:
point – Geographic location (latitude/longitude in radians)
utc_fraction – UTC time as fraction of day (0.0 = midnight, 0.5 = noon)
month – Month number (1-12)
- Returns:
Solar zenith angle in radians (0 = directly overhead, π/2 = horizon)
Note
Uses simplified solar position model appropriate for HF propagation
Solar latitude varies throughout month (linear interpolation)
Solar longitude calculated from UTC time
Example
>>> # Solar zenith at noon UTC on June 15 at equator >>> point = GeographicPoint(latitude=0, longitude=0) >>> zenith = compute_zenith_angle(point, 0.5, 6) # 0.5 = noon UTC >>> print(f"Zenith angle: {math.degrees(zenith):.1f}°")
- dvoacap.solar.compute_local_time(utc_fraction: float, longitude: float) float[source]¶
Calculate local time from UTC and longitude.
- Parameters:
utc_fraction – UTC time as fraction of day (0.0-1.0)
longitude – Longitude in radians (positive east)
- Returns:
Local time as fraction of day (0.0-1.0)
Note
VOACAP uses hours 1-24; 0h is never used
Returns 1.0 (not 0.0) for midnight to match VOACAP convention
Example
>>> # Local time at 90°W when UTC is noon >>> lon = -90 * (math.pi / 180) >>> local = compute_local_time(0.5, lon) >>> print(f"Local time: {local * 24:.1f}h")
- dvoacap.solar.is_daytime(zenith_angle: float, twilight_angle: float = 1.6755160819145565) bool[source]¶
Determine if it’s daytime at a location.
- Parameters:
zenith_angle – Solar zenith angle in radians
twilight_angle – Angle defining day/night boundary (default: 96°) 90° = geometric horizon 96° = civil twilight (typical for HF propagation) 102° = nautical twilight
- Returns:
True if daytime, False if nighttime
- dvoacap.solar.solar_elevation_angle(zenith_angle: float) float[source]¶
Convert zenith angle to elevation angle.
- Parameters:
zenith_angle – Solar zenith angle in radians
- Returns:
Solar elevation angle in radians (positive above horizon)
- dvoacap.solar.get_utc_fraction(dt: datetime) float[source]¶
Convert datetime to UTC fraction of day.
- Parameters:
dt – datetime object (assumed to be UTC)
- Returns:
Fraction of day (0.0 = midnight, 0.5 = noon, 1.0 = midnight next day)
Example
>>> from datetime import datetime >>> dt = datetime(2024, 6, 15, 12, 0) # Noon UTC >>> frac = get_utc_fraction(dt) >>> print(f"UTC fraction: {frac}") # Should be 0.5
- class dvoacap.solar.SolarCalculator[source]¶
Bases:
objectHigh-level interface for solar position calculations.
This class provides convenient methods for common solar calculations needed in HF propagation modeling.
- calculate_zenith_angle(location: GeographicPoint, time: datetime) float[source]¶
Calculate solar zenith angle at a location and time.
- Parameters:
location – Geographic point (lat/lon in radians)
time – UTC datetime
- Returns:
Solar zenith angle in radians
- is_daytime_at(location: GeographicPoint, time: datetime, twilight_deg: float = 96.0) bool[source]¶
Determine if it’s daytime at a location and time.
- Parameters:
location – Geographic point
time – UTC datetime
twilight_deg – Twilight angle in degrees (default: 96°)
- Returns:
True if daytime, False if nighttime
Geomagnetic Field¶
Geomagnetic Field Calculations Module for VOACAP Ported from MagFld.pas (DVOACAP)
Original Author: Alex Shovkoplyas, VE3NEA Python Port: 2025
This module calculates geomagnetic field parameters for HF propagation modeling: - Magnetic latitude - Gyrofrequency - Magnetic dip angle
- class dvoacap.geomagnetic.GeographicPoint(latitude: float, longitude: float)[source]¶
Bases:
objectGeographic location in radians
- classmethod from_degrees(lat_deg: float, lon_deg: float) GeographicPoint[source]¶
Create point from degrees
- class dvoacap.geomagnetic.GeomagneticParameters(magnetic_latitude: float, gyrofrequency: float, magnetic_dip: float, field_x: float, field_y: float, field_z: float)[source]¶
Bases:
objectResults of geomagnetic field calculations
- class dvoacap.geomagnetic.SinCos(sin: float, cos: float)[source]¶
Bases:
objectPaired sine and cosine values
- dvoacap.geomagnetic.make_sincos_array(x: float, length: int) tuple[SinCos, ...][source]¶
Generate array of sin/cos pairs for multiple angles.
This uses angle addition formulas to efficiently compute sin(n*x) and cos(n*x) for n = 0, 1, 2, …, length-1
- Parameters:
x – Base angle in radians
length – Number of terms to generate
- Returns:
Tuple of SinCos objects containing sin(n*x) and cos(n*x)
Note
Uses recurrence relation: sin((n+1)x) = sin(x)*cos(nx) + cos(x)*sin(nx) cos((n+1)x) = cos(x)*cos(nx) - sin(x)*sin(nx)
Cached with @cache decorator for performance (Python 3.11+)
- class dvoacap.geomagnetic.GeomagneticField[source]¶
Bases:
objectCalculate geomagnetic field parameters using spherical harmonic model.
This implements a simplified IGRF (International Geomagnetic Reference Field) model truncated to degree 6 for computational efficiency.
- compute_xyz(lat: float, lon: float) tuple[float, float, float][source]¶
Compute X, Y, Z components of magnetic field vector.
- Parameters:
lat – Latitude in radians
lon – Longitude in radians (east positive)
- Returns:
Tuple of (X, Y, Z) field components
Note
X: East component
Y: North component
Z: Vertical component (positive downward)
Uses spherical harmonic expansion to degree 6
- compute(location: GeographicPoint) GeomagneticParameters[source]¶
Compute all geomagnetic parameters for a location.
- Parameters:
location – Geographic point (lat/lon in radians)
- Returns:
GeomagneticParameters with all calculated values
Note
Calculates: - Magnetic latitude (for ionospheric modeling) - Gyrofrequency (electron gyrofrequency in MHz) - Magnetic dip angle (inclination)
- class dvoacap.geomagnetic.GeomagneticCalculator[source]¶
Bases:
objectHigh-level interface for geomagnetic calculations.
This class provides convenient methods for computing geomagnetic parameters needed in HF propagation modeling.
- calculate_parameters(location: GeographicPoint) GeomagneticParameters[source]¶
Calculate all geomagnetic parameters for a location.
- Parameters:
location – Geographic point
- Returns:
GeomagneticParameters with calculated values
- calculate_magnetic_latitude(lat_deg: float, lon_deg: float) float[source]¶
Calculate magnetic latitude in degrees.
- Parameters:
lat_deg – Geographic latitude in degrees
lon_deg – Geographic longitude in degrees
- Returns:
Magnetic latitude in degrees
Fourier Maps¶
Fourier Coefficient Maps Module for VOACAP Ported from FrMaps.pas (DVOACAP)
Original Author: Alex Shovkoplyas, VE3NEA Python Port: 2025
This module loads and processes CCIR/URSI ionospheric coefficient data: - Loads binary coefficient files for each month - Interpolates coefficients by sunspot number (SSN) and UTC time - Computes ionospheric parameters: foF2, foE, foEs, M3000F2 - Provides fixed maps (noise, land mass, YmF2) and variable maps
- class dvoacap.fourier_maps.FixedMapKind[source]¶
Bases:
objectTypes of fixed ionospheric maps
- NOISE1 = 0¶
- NOISE2 = 1¶
- NOISE3 = 2¶
- NOISE4 = 3¶
- NOISE5 = 4¶
- NOISE6 = 5¶
- LAND_MASS = 6¶
- YM_F2 = 7¶
- class dvoacap.fourier_maps.VarMapKind[source]¶
Bases:
objectTypes of variable ionospheric maps
- ES_U = 0¶
- ES_M = 1¶
- ES_L = 2¶
- F2 = 3¶
- FM3 = 4¶
- ER = 5¶
- dvoacap.fourier_maps.make_sincos_array(angle: float, count: int) List[Tuple[float, float]][source]¶
Generate array of sine and cosine values for Fourier series (vectorized).
- Parameters:
angle – Base angle in radians
count – Number of harmonics to generate
- Returns:
List of (sin, cos) tuples for each harmonic
- class dvoacap.fourier_maps.Distribution(median: float, hi: float, lo: float)[source]¶
Bases:
objectStatistical distribution with median and decile values
- class dvoacap.fourier_maps.FourierMaps(data_dir: str | None = None)[source]¶
Bases:
objectManages CCIR/URSI ionospheric coefficient maps.
This class loads binary coefficient data and computes ionospheric parameters using Fourier series expansions. The coefficients are interpolated for specific month, sunspot number, and UTC time.
Example
>>> maps = FourierMaps() >>> maps.set_conditions(month=6, ssn=100, utc_fraction=0.5) >>> fof2 = maps.compute_var_map(VarMapKind.F2, lat, lon, cos_lat)
- __init__(data_dir: str | None = None) None[source]¶
Initialize Fourier maps handler.
- Parameters:
data_dir – Path to DVoaData directory. If None, uses default location.
- set_conditions(month: int, ssn: float, utc_fraction: float) None[source]¶
Set month, sunspot number, and UTC time for coefficient interpolation.
- Parameters:
month – Month number (1-12)
ssn – Smoothed sunspot number (0-200+)
utc_fraction – UTC time as fraction of day (0.0-1.0)
- compute_fixed_map(kind: int, lat: float, east_lon: float) float[source]¶
Compute fixed ionospheric map value.
Fixed maps are noise levels, land mass, and YmF2 that don’t vary with UTC time but depend on SSN and month.
- Parameters:
kind – Map type (use FixedMapKind constants)
lat – Latitude in radians
east_lon – East longitude in radians
- Returns:
Map value (units depend on map type)
- compute_var_map(kind: int, lat: float, east_lon: float, cos_lat: float) float[source]¶
Compute variable ionospheric map value.
Variable maps include foF2, foE, foEs, M3000F2 that vary with month, SSN, and UTC time.
- Parameters:
kind – Map type (use VarMapKind constants)
lat – Latitude in radians (or magnetic dip for some maps)
east_lon – East longitude in radians
cos_lat – Cosine of latitude
- Returns:
Map value in MHz (for critical frequencies) or unitless (M3000)
- compute_zen_max(mag_dip: float) float[source]¶
Compute maximum solar zenith angle for F1 layer formation.
- Parameters:
mag_dip – Magnetic dip angle in radians
- Returns:
Maximum zenith angle in radians
- compute_fof1(zen_angle: float) float[source]¶
Compute F1 layer critical frequency.
- Parameters:
zen_angle – Solar zenith angle in radians
- Returns:
foF1 in MHz
- compute_f2_deviation(muf: float, lat: float, local_time: float, above: bool) float[source]¶
Compute F2 layer deviation for reliability calculations.
- Parameters:
muf – Maximum usable frequency in MHz
lat – Latitude in radians
local_time – Local time as fraction of day (0.0-1.0)
above – True for above MUF, False for below
- Returns:
Standard deviation in MHz
- compute_excessive_system_loss(mag_lat: float, local_time: float, over_2500km: bool) Distribution[source]¶
Compute excessive system loss distribution.
- Parameters:
mag_lat – Magnetic latitude in radians
local_time – Local time as fraction of day (0.0-1.0)
over_2500km – True if path > 2500 km
- Returns:
Distribution with median, hi, and lo values in dB
Layer Parameters¶
Layer Parameters Module for VOACAP Ported from LayrParm.pas (DVOACAP)
Original Author: Alex Shovkoplyas, VE3NEA Python Port: 2025
This module computes ionospheric layer parameters (E, F1, F2, Es) by combining CCIR/URSI maps with local solar/geomagnetic conditions.
- class dvoacap.layer_parameters.GeographicPoint(latitude: float, longitude: float)[source]¶
Bases:
objectGeographic location
- classmethod from_degrees(lat: float, lon: float) GeographicPoint[source]¶
Create from degrees
- class dvoacap.layer_parameters.ControlPoint(location: ~dvoacap.layer_parameters.GeographicPoint = <factory>, east_lon: float = 0.0, distance_rad: float = 0.0, local_time: float = 0.0, zen_angle: float = 0.0, zen_max: float = 0.0, mag_lat: float = 0.0, mag_dip: float = 0.0, gyro_freq: float = 0.0, gnd_sig: float = 0.005, gnd_eps: float = 15.0, e: ~dvoacap.ionospheric_profile.LayerInfo = None, f1: ~dvoacap.ionospheric_profile.LayerInfo = None, f2: ~dvoacap.ionospheric_profile.LayerInfo = None, es: ~dvoacap.ionospheric_profile.LayerInfo = None, es_fo_lo: float = 0.0, es_fo_hi: float = 0.0, absorp: float = 0.0, f2m3: float = 0.0, hpf2: float = 0.0, rat: float = 0.0)[source]¶
Bases:
objectControl point with location and ionospheric parameters.
This represents all the ionospheric conditions at a specific location and time along a propagation path.
- location: GeographicPoint¶
- __init__(location: ~dvoacap.layer_parameters.GeographicPoint = <factory>, east_lon: float = 0.0, distance_rad: float = 0.0, local_time: float = 0.0, zen_angle: float = 0.0, zen_max: float = 0.0, mag_lat: float = 0.0, mag_dip: float = 0.0, gyro_freq: float = 0.0, gnd_sig: float = 0.005, gnd_eps: float = 15.0, e: ~dvoacap.ionospheric_profile.LayerInfo = None, f1: ~dvoacap.ionospheric_profile.LayerInfo = None, f2: ~dvoacap.ionospheric_profile.LayerInfo = None, es: ~dvoacap.ionospheric_profile.LayerInfo = None, es_fo_lo: float = 0.0, es_fo_hi: float = 0.0, absorp: float = 0.0, f2m3: float = 0.0, hpf2: float = 0.0, rat: float = 0.0) None¶
- dvoacap.layer_parameters.compute_f2_retardation(pnt: ControlPoint) float[source]¶
Compute F2 layer retardation and adjust F1 layer if necessary.
The retardation accounts for the group delay through lower layers and adjusts the F2 peak height accordingly. Also handles twilight transitions for F1 layer.
- Parameters:
pnt – Control point with layer parameters
- Returns:
Total retardation in km
- dvoacap.layer_parameters.compute_iono_params(pnt: ControlPoint, maps: FourierMaps) None[source]¶
Compute all ionospheric layer parameters for a control point.
This is the main function that computes E, F1, F2, and Es layer parameters by querying the CCIR/URSI coefficient maps and applying corrections based on local conditions.
- Parameters:
pnt – Control point to compute parameters for
maps – FourierMaps object with loaded coefficients
The control point is modified in place with computed layer parameters.
Example
>>> from dvoacap import GeographicPoint >>> pnt = ControlPoint( ... location=GeographicPoint.from_degrees(40, -75), ... east_lon=-75 * RinD, ... local_time=0.5, ... zen_angle=0.3, ... mag_lat=50 * RinD, ... mag_dip=60 * RinD, ... gyro_freq=1.2 ... ) >>> maps = FourierMaps() >>> maps.set_conditions(month=6, ssn=100, utc_fraction=0.5) >>> compute_iono_params(pnt, maps) >>> print(f"foF2: {pnt.f2.fo:.2f} MHz")
Ionospheric Profile¶
Ionospheric Profile Module for VOACAP Ported from IonoProf.pas (DVOACAP)
Original Author: Alex Shovkoplyas, VE3NEA Python Port: 2025
This module models the electron density profile of the ionosphere: - E, F1, and F2 layer modeling with parabolic and linear profiles - True height and virtual height calculations - Ionogram generation - Deviative loss calculations - Penetration angle calculations
- class dvoacap.ionospheric_profile.LayerInfo(fo: float = 0.0, hm: float = 0.0, ym: float = 0.0)[source]¶
Bases:
objectInformation about an ionospheric layer
- class dvoacap.ionospheric_profile.Reflection(elevation: float = 0.0, true_height: float = 0.0, virt_height: float = 0.0, vert_freq: float = 0.0, dev_loss: float = 0.0)[source]¶
Bases:
objectReflection point information
- class dvoacap.ionospheric_profile.ModeInfo(ref: Reflection = None, hop_dist: float = 0.0, hop_cnt: int = 0, layer: str = '', signal: SignalInfo = None)[source]¶
Bases:
objectPropagation mode information
- ref: Reflection = None¶
- signal: SignalInfo = None¶
- __init__(ref: Reflection = None, hop_dist: float = 0.0, hop_cnt: int = 0, layer: str = '', signal: SignalInfo = None) None¶
- dvoacap.ionospheric_profile.interpolate_linear(arr: ndarray, start_h: int, end_h: int) None[source]¶
Populate array with linearly interpolated data
- dvoacap.ionospheric_profile.corr_to_martyns_theorem(ref: Reflection) float[source]¶
Apply Martyn’s theorem correction.
- Parameters:
ref – Reflection point information
- Returns:
Correction factor
- dvoacap.ionospheric_profile.get_index_of(value: float, array: ndarray) int[source]¶
Find index of value in array.
- Parameters:
value – Value to find
array – Array to search
- Returns:
Index of nearest value
- dvoacap.ionospheric_profile.interpolate_table(x: float, arr_x: ndarray, arr_y: ndarray) float[source]¶
Interpolate value from lookup table.
- Parameters:
x – Input value
arr_x – X values (argument)
arr_y – Y values (function)
- Returns:
Interpolated Y value
- class dvoacap.ionospheric_profile.IonosphericProfile[source]¶
Bases:
objectModels the electron density profile of the ionosphere.
This class creates a detailed model of electron density vs height for E, F1, and F2 layers, then uses this to compute true and virtual heights, ionograms, and propagation parameters.
Example
>>> profile = IonosphericProfile() >>> profile.e = LayerInfo(fo=3.0, hm=110, ym=20) >>> profile.f2 = LayerInfo(fo=8.0, hm=300, ym=100) >>> profile.compute_el_density_profile() >>> true_h = profile.get_true_height(5.0) # MHz
- compute_el_density_profile() None[source]¶
Compute the electron density profile.
This analyzes the layer parameters and creates arrays of electron density vs true height for the entire ionosphere from D layer through F2 layer.
- get_true_height(mhz: float) float[source]¶
Get true height for given frequency.
- Parameters:
mhz – Frequency in MHz
- Returns:
True height in km
- get_virtual_height_gauss(mhz: float) float[source]¶
Get virtual height using Gaussian integration (vectorized).
Virtual height is computed by integrating the group path from the ground to the reflection height.
- Parameters:
mhz – Frequency in MHz
- Returns:
Virtual height in km
- compute_ionogram() None[source]¶
Compute ionogram (true and virtual height vs frequency).
Generates arrays of frequencies and corresponding true/virtual heights that describe the ionospheric profile.
- compute_penetration_angles(mhz: float) dict[str, float][source]¶
Compute penetration angles for each layer.
- Parameters:
mhz – Frequency in MHz
- Returns:
Dictionary mapping layer name to penetration angle in radians
- compute_oblique_frequencies() None[source]¶
Compute oblique reflection frequencies for all angles and heights (vectorized).
This creates a 2D array oblique_freq[angle_idx, height_idx] that stores the maximum frequency (in kHz) that can be reflected at each angle and height.
- compute_derivative_loss(muf_info: dict[str, Any]) None[source]¶
Compute derivative loss for the ionospheric profile.
This is a stub implementation. The full calculation is complex and involves layer parameters and MUF information. Currently sets dev_loss to a simple array of zeros.
- Parameters:
muf_info – Dictionary of MUF information for each layer
MUF Calculator¶
MUF Calculator Module for VOACAP Ported from MufCalc.pas (DVOACAP)
Original Author: Alex Shovkoplyas, VE3NEA Python Port: 2025
This module computes Maximum Usable Frequency (MUF) for HF propagation: - Circuit MUF calculations for E, F1, F2 layers - FOT (Frequency of Optimum Traffic) and HPF calculations - MUF probability distributions - First estimate and iterative refinement algorithms
- class dvoacap.muf_calculator.MufInfo(ref: Reflection, hop_count: int = 1, fot: float = 0.0, hpf: float = 0.0, muf: float = 0.0, sig_lo: float = 0.0, sig_hi: float = 0.0)[source]¶
Bases:
objectMUF information for a single layer
- ref: Reflection¶
- class dvoacap.muf_calculator.CircuitMuf(muf_info: dict[str, MufInfo], fot: float = 0.0, muf: float = 0.0, hpf: float = 0.0, angle: float = 0.0, layer: str = 'F2')[source]¶
Bases:
objectCircuit MUF for all layers
- dvoacap.muf_calculator.select_profile(profiles: list[IonosphericProfile]) IonosphericProfile | None[source]¶
Select the controlling profile from multiple sample areas.
From VOACAP: SELECT CONTROLING SAMPLE AREA
- Parameters:
profiles – List of ionospheric profiles (1, 2, or 3 profiles)
- Returns:
Selected profile or None
- dvoacap.muf_calculator.calc_muf_prob(freq: float, mode_muf: float, median: float, sigma_lo: float, sigma_hi: float) float[source]¶
Calculate probability that MUF exceeds the operating frequency.
- Parameters:
freq – Operating frequency (MHz)
mode_muf – MUF at a set angle for a particular layer (MHz)
median – Where median of distribution is placed (FOT, MUF or HPF)
sigma_lo – Lower decile standard deviation
sigma_hi – Upper decile standard deviation
- Returns:
Probability that MUF exceeds freq (0.0 to 1.0)
- class dvoacap.muf_calculator.MufCalculator(path: PathGeometry, maps: FourierMaps, min_angle: float = 0.05235987755982989)[source]¶
Bases:
objectCalculate Maximum Usable Frequency (MUF) for HF circuit.
This class computes MUF, FOT, and HPF for all ionospheric layers along a propagation path.
- __init__(path: PathGeometry, maps: FourierMaps, min_angle: float = 0.05235987755982989)[source]¶
Initialize MUF calculator.
- Parameters:
path – PathGeometry object with Tx/Rx locations
maps – FourierMaps object for ionospheric parameters
min_angle – Minimum elevation angle (radians), default 3°
- compute_circuit_muf(profiles: list[IonosphericProfile]) CircuitMuf[source]¶
Compute circuit MUF for all layers.
- Parameters:
profiles – List of ionospheric profiles (typically 1-3)
- Returns:
CircuitMuf object with MUF for all layers
Reflectrix (Raytracing)¶
Reflectrix (Raytracing) Module for VOACAP Ported from Reflx.pas (DVOACAP)
Original Author: Alex Shovkoplyas, VE3NEA Python Port: 2025
This module performs ray path calculations through the ionosphere: - Ray reflection calculations for E, F1, F2 layers - Skip distance computation - Multi-hop path finding - Reflectrix (frequency vs elevation angle) - Over-the-MUF and vertical mode calculations
- class dvoacap.reflectrix.Reflectrix(min_angle: float, freq: float, profile: IonosphericProfile)[source]¶
Bases:
objectComputes ray paths (reflectrix) through the ionosphere.
The reflectrix is a graph of elevation angle vs ground distance for a given frequency, showing all possible propagation modes.
- __init__(min_angle: float, freq: float, profile: IonosphericProfile)[source]¶
Initialize reflectrix calculator.
- Parameters:
min_angle – Minimum elevation angle (radians)
freq – Frequency (MHz)
profile – Ionospheric profile
- compute_reflectrix(freq_mhz: float, profile: IonosphericProfile) None[source]¶
Compute reflectrix (all modes) for a given frequency.
- Parameters:
freq_mhz – Frequency in MHz
profile – Ionospheric profile
Noise Model¶
DVOACAP Noise Model - Phase 5
This module implements radio noise modeling for HF propagation predictions, including atmospheric, galactic, and man-made noise sources.
Based on ITU-R P.372 noise models and VOACAP’s NoiseMdl.pas implementation.
Author: Ported from VOACAP Pascal source (VE3NEA)
- class dvoacap.noise_model.TripleValue(median: float = 0.0, lower: float = 0.0, upper: float = 0.0)[source]¶
Bases:
objectStatistical distribution with median and deciles.
- class dvoacap.noise_model.Distribution[source]¶
Bases:
objectComplete statistical distribution with values and errors.
- value: TripleValue¶
- error: TripleValue¶
- class dvoacap.noise_model.NoiseModel(fourier_maps: FourierMaps)[source]¶
Bases:
objectRadio noise model implementing atmospheric, galactic, and man-made noise calculations.
The model computes noise power distributions as a function of frequency, location, and time of day, following ITU recommendations.
- man_made_noise_at_3mhz¶
Man-made noise level at 3 MHz (dB above kTB)
- atmospheric_noise¶
Atmospheric noise distribution
- galactic_noise¶
Galactic (cosmic) noise distribution
- man_made_noise¶
Man-made (industrial) noise distribution
- combined_noise¶
Combined noise from all sources
- TWO_PI = 6.283185307179586¶
- DB_IN_NP = 4.34294¶
- NP_IN_DB = 0.23025876479988214¶
- NORM_DECILE = 1.28¶
- __init__(fourier_maps: FourierMaps)[source]¶
Initialize the noise model.
- Parameters:
fourier_maps – FourierMaps instance for accessing coefficient data
- compute_noise_at_1mhz(location: GeoPoint, local_time: float) None[source]¶
Prepare 1MHz noise coefficients for use in compute_distribution.
This method computes and caches the atmospheric noise parameters at 1 MHz, which are then scaled for other frequencies in compute_distribution().
- Parameters:
location – Geographic location (lat/lon in radians)
local_time – Local time as fraction of day (0.0 to 1.0)
- compute_distribution(frequency: float, fof2: float) None[source]¶
Compute noise probability density functions for a specific frequency.
This method calculates atmospheric, galactic, and man-made noise distributions, then combines them into a total noise distribution with median and decile values.
- Parameters:
frequency – Operating frequency in MHz
fof2 – F2 layer critical frequency in MHz (for galactic noise penetration)
Antenna Gain¶
DVOACAP Antenna Gain Module - Phase 5
This module implements antenna gain calculations for HF propagation predictions. Provides base classes for antenna models with elevation and azimuth-dependent gain patterns.
Based on VOACAP’s AntGain.pas implementation.
Author: Ported from VOACAP Pascal source (VE3NEA)
- class dvoacap.antenna_gain.AntennaModel(low_frequency: float = 0.0, high_frequency: float = 1000000000.0, extra_gain_db: float = 0.0, tx_power_dbw: float = 1.0)[source]¶
Bases:
objectBase class for antenna gain models.
Provides interface for computing antenna gain as a function of elevation angle, azimuth, and frequency. Subclasses can implement specific antenna patterns.
- extra_gain_db¶
Additional gain to add to computed gain (dB)
- tx_power_dbw¶
Transmit power in dBW
- __init__(low_frequency: float = 0.0, high_frequency: float = 1000000000.0, extra_gain_db: float = 0.0, tx_power_dbw: float = 1.0) None[source]¶
Initialize antenna model.
- Parameters:
low_frequency – Lower frequency limit in MHz (default: 0)
high_frequency – Upper frequency limit in MHz (default: very large)
extra_gain_db – Extra gain in dB to add to result (default: 0)
tx_power_dbw – Transmit power in dBW (default: 1 = 10W)
- class dvoacap.antenna_gain.IsotropicAntenna(tx_power_dbw: float = 1.0)[source]¶
Bases:
AntennaModelIsotropic antenna model (0 dBi gain in all directions).
This is the default antenna used when no specific antenna is selected for a given frequency range.
- class dvoacap.antenna_gain.AntennaFarm[source]¶
Bases:
objectAntenna farm manager for selecting appropriate antenna based on frequency.
Manages a collection of antennas with different frequency ranges and automatically selects the appropriate antenna for each operating frequency. If no antenna covers the requested frequency, an isotropic antenna is used.
- antennas¶
List of available antenna models
- property current_antenna: AntennaModel¶
Get currently selected antenna.
- add_antenna(antenna: AntennaModel) None[source]¶
Add an antenna to the farm.
- Parameters:
antenna – AntennaModel instance to add
- select_antenna(frequency: float) None[source]¶
Select antenna for specified frequency.
Searches through available antennas and selects the first one whose frequency range includes the specified frequency. If no suitable antenna is found, the isotropic antenna is selected.
- Parameters:
frequency – Operating frequency in MHz
- class dvoacap.antenna_gain.HalfWaveDipole(low_frequency: float, high_frequency: float, tx_power_dbw: float = 1.0)[source]¶
Bases:
AntennaModelHalf-wave dipole antenna model.
Simple dipole antenna with frequency-dependent gain pattern. Peak gain is approximately 2.15 dBi at the horizon.
- class dvoacap.antenna_gain.VerticalMonopole(low_frequency: float, high_frequency: float, tx_power_dbw: float = 1.0)[source]¶
Bases:
AntennaModelVertical monopole antenna model.
Ground-mounted vertical antenna with omnidirectional azimuth pattern. Good low-angle radiation for DX communications.
- class dvoacap.antenna_gain.InvertedVDipole(low_frequency: float, high_frequency: float, tx_power_dbw: float = 1.0)[source]¶
Bases:
AntennaModelInverted V dipole antenna model.
Similar to half-wave dipole but with drooping elements. Better low-angle radiation than horizontal dipole. Peak gain around 3-4 dBi at moderate elevation angles.
- class dvoacap.antenna_gain.ThreeElementYagi(low_frequency: float, high_frequency: float, tx_power_dbw: float = 1.0)[source]¶
Bases:
AntennaModel3-element Yagi antenna model.
Directional beam antenna with higher gain than dipoles. Excellent for DX work with proper aiming. Peak gain around 7-8 dBi at low to moderate elevation angles.
- dvoacap.antenna_gain.create_antenna(antenna_type: str, low_frequency: float, high_frequency: float, tx_power_dbw: float = 1.0) AntennaModel[source]¶
Factory function to create antenna models by type name.
- Parameters:
antenna_type – Type of antenna (‘vertical’, ‘dipole’, ‘inverted-v’, ‘yagi’, ‘isotropic’)
low_frequency – Lower frequency limit in MHz
high_frequency – Upper frequency limit in MHz
tx_power_dbw – Transmit power in dBW (default: 1 = 10W)
- Returns:
Appropriate AntennaModel instance
- Raises:
ValueError – If antenna_type is not recognized
Prediction Engine¶
DVOACAP Prediction Engine - Phase 5
This module implements the complete HF radio propagation prediction engine, integrating all phases (1-5) to compute signal strength, reliability, and system performance metrics.
Based on VOACAP’s VoaCapEng.pas implementation.
Author: Ported from VOACAP Pascal source (VE3NEA)
- class dvoacap.prediction_engine.IonosphericLayer(value)[source]¶
Bases:
EnumIonospheric layer types.
- E = 0¶
- F1 = 1¶
- F2 = 2¶
- class dvoacap.prediction_engine.PredictionMethod(value)[source]¶
Bases:
EnumMethod used for prediction.
- SHORT = 'short'¶
- LONG = 'long'¶
- SMOOTH = 'smooth'¶
- class dvoacap.prediction_engine.SignalInfo(delay_ms: float = 0.0, tx_gain_db: float = 0.0, rx_gain_db: float = 0.0, muf_day: float = 0.0, total_loss_db: float = 0.0, power10: float = 0.0, power90: float = 0.0, field_dbuv: float = 0.0, power_dbw: float = 0.0, snr_db: float = 0.0, snr10: float = 0.0, snr90: float = 0.0, reliability: float = 0.0)[source]¶
Bases:
objectComplete signal information for a propagation mode.
- __init__(delay_ms: float = 0.0, tx_gain_db: float = 0.0, rx_gain_db: float = 0.0, muf_day: float = 0.0, total_loss_db: float = 0.0, power10: float = 0.0, power90: float = 0.0, field_dbuv: float = 0.0, power_dbw: float = 0.0, snr_db: float = 0.0, snr10: float = 0.0, snr90: float = 0.0, reliability: float = 0.0) None¶
- class dvoacap.prediction_engine.ModeInfo(reflection: ~dvoacap.ionospheric_profile.Reflection = <factory>, signal: ~dvoacap.prediction_engine.SignalInfo = <factory>, hop_distance: float = 0.0, hop_count: int = 0, layer: ~dvoacap.prediction_engine.IonosphericLayer = IonosphericLayer.F2, free_space_loss: float = 0.0, absorption_loss: float = 0.0, obscuration: float = 0.0, deviation_term: float = 0.0, ground_loss: float = 0.0)[source]¶
Bases:
objectInformation about a single propagation mode.
- reflection: Reflection¶
- signal: SignalInfo¶
- layer: IonosphericLayer = 2¶
- __init__(reflection: ~dvoacap.ionospheric_profile.Reflection = <factory>, signal: ~dvoacap.prediction_engine.SignalInfo = <factory>, hop_distance: float = 0.0, hop_count: int = 0, layer: ~dvoacap.prediction_engine.IonosphericLayer = IonosphericLayer.F2, free_space_loss: float = 0.0, absorption_loss: float = 0.0, obscuration: float = 0.0, deviation_term: float = 0.0, ground_loss: float = 0.0) None¶
- class dvoacap.prediction_engine.Prediction(method: ~dvoacap.prediction_engine.PredictionMethod = PredictionMethod.SHORT, mode_tx: ~dvoacap.prediction_engine.IonosphericLayer = IonosphericLayer.F2, mode_rx: ~dvoacap.prediction_engine.IonosphericLayer = IonosphericLayer.F2, hop_count: int = 0, tx_elevation: float = 0.0, rx_elevation: float = 0.0, virt_height: float = 0.0, signal: ~dvoacap.prediction_engine.SignalInfo = <factory>, noise_dbw: float = 0.0, required_power: float = 0.0, multipath_prob: float = 0.0, service_prob: float = 0.0, snr_xx: float = 0.0)[source]¶
Bases:
objectComplete propagation prediction for one frequency.
- method: PredictionMethod = 'short'¶
- mode_tx: IonosphericLayer = 2¶
- mode_rx: IonosphericLayer = 2¶
- signal: SignalInfo¶
- __init__(method: ~dvoacap.prediction_engine.PredictionMethod = PredictionMethod.SHORT, mode_tx: ~dvoacap.prediction_engine.IonosphericLayer = IonosphericLayer.F2, mode_rx: ~dvoacap.prediction_engine.IonosphericLayer = IonosphericLayer.F2, hop_count: int = 0, tx_elevation: float = 0.0, rx_elevation: float = 0.0, virt_height: float = 0.0, signal: ~dvoacap.prediction_engine.SignalInfo = <factory>, noise_dbw: float = 0.0, required_power: float = 0.0, multipath_prob: float = 0.0, service_prob: float = 0.0, snr_xx: float = 0.0) None¶
- class dvoacap.prediction_engine.VoacapParams(ssn: float = 100.0, month: int = 1, tx_location: ~dvoacap.path_geometry.GeoPoint = <factory>, tx_power: float = 1500.0, min_angle: float = np.float64(0.05235987755982989), man_made_noise_at_3mhz: float = 145.0, long_path: bool = False, required_snr: float = 73.0, required_reliability: float = 0.9, multipath_power_tolerance: float = 3.0, max_tolerable_delay: float = 0.1, bandwidth_hz: float = 2700.0)[source]¶
Bases:
objectVOACAP input parameters.
- __init__(ssn: float = 100.0, month: int = 1, tx_location: ~dvoacap.path_geometry.GeoPoint = <factory>, tx_power: float = 1500.0, min_angle: float = np.float64(0.05235987755982989), man_made_noise_at_3mhz: float = 145.0, long_path: bool = False, required_snr: float = 73.0, required_reliability: float = 0.9, multipath_power_tolerance: float = 3.0, max_tolerable_delay: float = 0.1, bandwidth_hz: float = 2700.0) None¶
- class dvoacap.prediction_engine.PredictionEngine[source]¶
Bases:
objectComplete VOACAP prediction engine.
Integrates all phases to compute HF radio propagation predictions including signal strength, reliability, and system performance metrics.
Example
>>> engine = PredictionEngine() >>> engine.params.tx_location = GeoPoint(lat=40.0*np.pi/180, lon=-75.0*np.pi/180) >>> rx_location = GeoPoint(lat=51.5*np.pi/180, lon=-0.1*np.pi/180) >>> engine.predict(rx_location, utc_time=0.5, frequencies=[7.0, 14.0, 21.0]) >>> for freq, pred in zip(engine.frequencies, engine.predictions): ... print(f"{freq} MHz: SNR={pred.signal.snr_db:.1f} dB")
- EARTH_RADIUS = 6370.0¶
- VELOCITY_OF_LIGHT = 299.79246¶
- DB_IN_NP = 4.34294¶
- NP_IN_DB = 0.23025876479988214¶
- NORM_DECILE = 1.28¶
- RAD_1000_KM = 0.15698587127158556¶
- RAD_2000_KM = 0.3139717425431711¶
- RAD_2000_KM_01 = 0.3139733124018838¶
- RAD_2500_KM = 0.3924646781789639¶
- RAD_4000_KM = 0.6279434850863422¶
- RAD_7000_KM = 1.098901098901099¶
- RAD_10000_KM = 1.5698587127158556¶
- HTLOSS = 88.0¶
- XNUZ = 63.07¶
- HNU = 4.39¶
- TME = array([0. , 0.1257, 0.2533, 0.3853, 0.5244, 0.6745, 0.8416, 1.0364, 1.2815, 1.6449])¶
- NANGX = array([40, 34, 29, 24, 19, 14, 12, 9])¶
VOACAP Parser¶
VOACAP Binary File Parser
This module provides functionality to parse VOACAP binary coefficient data files. These files contain Fourier coefficients for ionospheric models used in HF radio propagation predictions.
Binary file formats: - Coeff##.dat: Monthly ionospheric coefficient data (38,480 bytes) - FOF2CCIR##.dat: F2 critical frequency data (7,904 bytes)
Author: Port from Pascal implementation by Alex Shovkoplyas, VE3NEA License: Mozilla Public License Version 1.1
- class dvoacap.voacap_parser.VarMapKind(value)[source]¶
Bases:
IntEnumTypes of variable ionospheric maps
- VM_ES_U = 0¶
- VM_ES_M = 1¶
- VM_ES_L = 2¶
- VM_F2 = 3¶
- VM_FM3 = 4¶
- VM_ER = 5¶
- class dvoacap.voacap_parser.FixedMapKind(value)[source]¶
Bases:
IntEnumTypes of fixed ionospheric maps
- FM_NOISE1 = 0¶
- FM_NOISE2 = 1¶
- FM_NOISE3 = 2¶
- FM_NOISE4 = 3¶
- FM_NOISE5 = 4¶
- FM_NOISE6 = 5¶
- FM_LAND_MASS = 6¶
- FM_YM_F2 = 7¶
- class dvoacap.voacap_parser.FixedCoeff[source]¶
Bases:
objectFixed coefficient data structure.
This corresponds to the TFixedCoeff record in FrMaps.pas. Contains arrays used for computing fixed ionospheric maps.
- class dvoacap.voacap_parser.CoeffData[source]¶
Bases:
objectComplete coefficient data for one month.
This corresponds to the data loaded by TFourierMaps.LoadCoeffResource() from the Coeff##.dat files.
- class dvoacap.voacap_parser.F2Data[source]¶
Bases:
objectF2 critical frequency coefficient data.
This corresponds to the data loaded from FOF2CCIR##.dat files.
- class dvoacap.voacap_parser.VoacapParser[source]¶
Bases:
objectParser for VOACAP binary coefficient data files.
This class provides methods to read and parse the binary coefficient files used by VOACAP for ionospheric propagation predictions.
- static parse_coeff_file(filepath: Path) CoeffData[source]¶
Parse a Coeff##.dat binary file.
- Parameters:
filepath – Path to the Coeff##.dat file
- Returns:
CoeffData object containing all coefficient arrays
- Raises:
FileNotFoundError – If the file doesn’t exist
ValueError – If the file size is incorrect
- static parse_f2_file(filepath: Path) F2Data[source]¶
Parse a FOF2CCIR##.dat binary file.
- Parameters:
filepath – Path to the FOF2CCIR##.dat file
- Returns:
F2Data object containing F2 coefficient arrays
- Raises:
FileNotFoundError – If the file doesn’t exist
ValueError – If the file size is incorrect
- static load_monthly_data(data_dir: Path, month: int) tuple[CoeffData, F2Data][source]¶
Load both coefficient and F2 data files for a given month.
- Parameters:
data_dir – Directory containing the DVoaData files
month – Month number (1-12)
- Returns:
Tuple of (CoeffData, F2Data)
- Raises:
ValueError – If month is not in range 1-12
FileNotFoundError – If data files don’t exist
- dvoacap.voacap_parser.load_coeff_file(filepath: str) CoeffData[source]¶
Load a Coeff##.dat file.
- Parameters:
filepath – Path to the coefficient file
- Returns:
CoeffData object