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: object

Geographic point with latitude and longitude in radians

lat: float
lon: float
classmethod from_degrees(lat_deg: float, lon_deg: float) GeoPoint[source]

Create GeoPoint from degrees

to_degrees() tuple[float, float][source]

Convert to degrees (lat, lon)

__init__(lat: float, lon: float) None
dvoacap.path_geometry.sign(x: float) float[source]

Return sign of x: 1 if x >= 0, else -1

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: object

Handles 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

__init__()[source]
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

hop_count(elev: float, height: float) int[source]

Calculate the number of hops required for given elevation angle and height.

Parameters:
  • elev – Elevation angle in radians

  • height – Virtual height in km

Returns:

Number of hops required

get_distance_km() float[source]

Get great circle distance in kilometers

get_azimuth_tr_degrees() float[source]

Get azimuth from Tx to Rx in degrees

get_azimuth_rt_degrees() float[source]

Get azimuth from Rx to Tx in degrees

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

dvoacap.path_geometry.cos_of_incidence(elev: float, height: float) float[source]

Calculate cosine of incidence angle at ionosphere.

Parameters:
  • elev – Elevation angle in radians

  • height – Height in km

Returns:

Cos of incidence angle

dvoacap.path_geometry.example_usage()[source]

Demonstrate usage of the PathGeometry module

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: object

Geographic location in radians

latitude: float
longitude: float
classmethod from_degrees(lat_deg: float, lon_deg: float) GeographicPoint[source]

Create point from degrees

__init__(latitude: float, longitude: float) None
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: object

High-level interface for solar position calculations.

This class provides convenient methods for common solar calculations needed in HF propagation modeling.

__init__() None[source]

Initialize solar calculator

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

calculate_local_time(longitude_deg: float, utc_time: datetime) float[source]

Calculate local time at a longitude.

Parameters:
  • longitude_deg – Longitude in degrees (positive east)

  • utc_time – UTC datetime

Returns:

Local time as fraction of day

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: object

Geographic location in radians

latitude: float
longitude: float
classmethod from_degrees(lat_deg: float, lon_deg: float) GeographicPoint[source]

Create point from degrees

__init__(latitude: float, longitude: float) None
class dvoacap.geomagnetic.GeomagneticParameters(magnetic_latitude: float, gyrofrequency: float, magnetic_dip: float, field_x: float, field_y: float, field_z: float)[source]

Bases: object

Results of geomagnetic field calculations

magnetic_latitude: float
gyrofrequency: float
magnetic_dip: float
field_x: float
field_y: float
field_z: float
__init__(magnetic_latitude: float, gyrofrequency: float, magnetic_dip: float, field_x: float, field_y: float, field_z: float) None
class dvoacap.geomagnetic.SinCos(sin: float, cos: float)[source]

Bases: object

Paired sine and cosine values

sin: float
cos: float
__init__(sin: float, cos: float) None
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: object

Calculate geomagnetic field parameters using spherical harmonic model.

This implements a simplified IGRF (International Geomagnetic Reference Field) model truncated to degree 6 for computational efficiency.

__init__() None[source]

Initialize geomagnetic field calculator

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: object

High-level interface for geomagnetic calculations.

This class provides convenient methods for computing geomagnetic parameters needed in HF propagation modeling.

__init__() None[source]

Initialize geomagnetic calculator

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

calculate_dip_angle(lat_deg: float, lon_deg: float) float[source]

Calculate magnetic dip angle in degrees.

Parameters:
  • lat_deg – Geographic latitude in degrees

  • lon_deg – Geographic longitude in degrees

Returns:

Magnetic dip angle in degrees (positive = downward in NH)

calculate_gyrofrequency(lat_deg: float, lon_deg: float) float[source]

Calculate electron gyrofrequency in MHz.

Parameters:
  • lat_deg – Geographic latitude in degrees

  • lon_deg – Geographic longitude in degrees

Returns:

Gyrofrequency in MHz

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: object

Types 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: object

Types 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: object

Statistical distribution with median and decile values

median: float
hi: float
lo: float
classmethod with_error(value_mdn: float, value_hi: float, value_lo: float, error_mdn: float, error_hi: float, error_lo: float) Distribution[source]

Create distribution with separate value and error components

__init__(median: float, hi: float, lo: float) None
class dvoacap.fourier_maps.FourierMaps(data_dir: str | None = None)[source]

Bases: object

Manages 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

compute_fam(idx1: int, idx2: int, u: float) float[source]

Compute FAM noise parameter using polynomial.

Parameters:
  • idx1 – First index (0-11)

  • idx2 – Second index (0-1)

  • u – Parameter value

Returns:

FAM value

compute_dud(idx1: int, idx2: int, u: float) float[source]

Compute DUD noise parameter using polynomial.

Parameters:
  • idx1 – First index (0-4)

  • idx2 – Second index (0-11)

  • u – Parameter value

Returns:

DUD value

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: object

Geographic location

latitude: float
longitude: float
classmethod from_degrees(lat: float, lon: float) GeographicPoint[source]

Create from degrees

__init__(latitude: float, longitude: float) None
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: object

Control point with location and ionospheric parameters.

This represents all the ionospheric conditions at a specific location and time along a propagation path.

location: GeographicPoint
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: LayerInfo = None
f1: LayerInfo = None
f2: LayerInfo = None
es: 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
__post_init__()[source]

Initialize layer info objects

__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: object

Information about an ionospheric layer

fo: float = 0.0
hm: float = 0.0
ym: float = 0.0
__init__(fo: float = 0.0, hm: float = 0.0, ym: float = 0.0) None
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: object

Reflection point information

elevation: float = 0.0
true_height: float = 0.0
virt_height: float = 0.0
vert_freq: float = 0.0
dev_loss: float = 0.0
__init__(elevation: float = 0.0, true_height: float = 0.0, virt_height: float = 0.0, vert_freq: float = 0.0, dev_loss: float = 0.0) None
class dvoacap.ionospheric_profile.ModeInfo(ref: Reflection = None, hop_dist: float = 0.0, hop_cnt: int = 0, layer: str = '', signal: SignalInfo = None)[source]

Bases: object

Propagation mode information

ref: Reflection = None
hop_dist: float = 0.0
hop_cnt: int = 0
layer: str = ''
signal: SignalInfo = None
__post_init__()[source]

Initialize ref and signal if not provided

__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: object

Models 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
__init__()[source]
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

populate_mode_info(mode: ModeInfo, idx: int, r: float = 0.0) None[source]

Populate mode information from ionogram data.

Parameters:
  • mode – ModeInfo object to populate (modified in place)

  • idx – Index in ionogram arrays

  • r – Interpolation ratio (0.0 = use idx, 1.0 = use idx+1)

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: object

MUF information for a single layer

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
__post_init__()[source]

Ensure ref is a Reflection object

__init__(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) None
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: object

Circuit MUF for all layers

muf_info: dict[str, MufInfo]
fot: float = 0.0
muf: float = 0.0
hpf: float = 0.0
angle: float = 0.0
layer: str = 'F2'
__init__(muf_info: dict[str, MufInfo], fot: float = 0.0, muf: float = 0.0, hpf: float = 0.0, angle: float = 0.0, layer: str = 'F2') None
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: object

Calculate 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

dvoacap.muf_calculator.example_usage()[source]

Demonstrate usage of the MUF Calculator module

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: object

Computes 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

find_modes(hop_dist: float, hop_cnt: int) None[source]

Find propagation modes for a specific hop distance.

Parameters:
  • hop_dist – Single hop ground distance (radians)

  • hop_cnt – Number of hops

add_over_the_muf_and_vert_modes(hop_dist: float, hop_cnt: int, circuit_muf: CircuitMuf) None[source]

Add over-the-MUF and vertical incidence modes.

Parameters:
  • hop_dist – Single hop ground distance (radians)

  • hop_cnt – Number of hops

  • circuit_muf – Circuit MUF information

dvoacap.reflectrix.example_usage()[source]

Demonstrate usage of the Reflectrix module

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: object

Statistical distribution with median and deciles.

median: float = 0.0
lower: float = 0.0
upper: float = 0.0
__init__(median: float = 0.0, lower: float = 0.0, upper: float = 0.0) None
class dvoacap.noise_model.Distribution[source]

Bases: object

Complete statistical distribution with values and errors.

__init__()[source]
value: TripleValue
error: TripleValue
class dvoacap.noise_model.NoiseModel(fourier_maps: FourierMaps)[source]

Bases: object

Radio 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)

property combined: float

Get median combined noise level in dB.

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: object

Base 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)

property frequency: float

Get current operating frequency in MHz.

property azimuth: float

Get antenna azimuth in radians.

property low_frequency: float

Get lower frequency limit in MHz.

property high_frequency: float

Get upper frequency limit in MHz.

get_gain_db(elevation: float) float[source]

Get antenna gain at specified elevation angle.

This base implementation returns only the extra gain. Subclasses should override to implement specific antenna patterns.

Parameters:

elevation – Elevation angle in radians

Returns:

Antenna gain in dBi

class dvoacap.antenna_gain.IsotropicAntenna(tx_power_dbw: float = 1.0)[source]

Bases: AntennaModel

Isotropic 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.

__init__(tx_power_dbw: float = 1.0) None[source]

Initialize isotropic antenna.

Parameters:

tx_power_dbw – Transmit power in dBW (default: 1 = 10W)

get_gain_db(elevation: float) float[source]

Get isotropic antenna gain (always 0 dBi).

Parameters:

elevation – Elevation angle in radians (unused)

Returns:

0.0 dBi (isotropic gain)

class dvoacap.antenna_gain.AntennaFarm[source]

Bases: object

Antenna 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

__init__() None[source]

Initialize antenna farm with isotropic default antenna.

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: AntennaModel

Half-wave dipole antenna model.

Simple dipole antenna with frequency-dependent gain pattern. Peak gain is approximately 2.15 dBi at the horizon.

__init__(low_frequency: float, high_frequency: float, tx_power_dbw: float = 1.0) None[source]

Initialize half-wave dipole antenna.

Parameters:
  • low_frequency – Lower frequency limit in MHz

  • high_frequency – Upper frequency limit in MHz

  • tx_power_dbw – Transmit power in dBW (default: 1 = 10W)

get_gain_db(elevation: float) float[source]

Get dipole antenna gain at specified elevation.

Parameters:

elevation – Elevation angle in radians

Returns:

Antenna gain in dBi

class dvoacap.antenna_gain.VerticalMonopole(low_frequency: float, high_frequency: float, tx_power_dbw: float = 1.0)[source]

Bases: AntennaModel

Vertical monopole antenna model.

Ground-mounted vertical antenna with omnidirectional azimuth pattern. Good low-angle radiation for DX communications.

__init__(low_frequency: float, high_frequency: float, tx_power_dbw: float = 1.0) None[source]

Initialize vertical monopole antenna.

Parameters:
  • low_frequency – Lower frequency limit in MHz

  • high_frequency – Upper frequency limit in MHz

  • tx_power_dbw – Transmit power in dBW (default: 1 = 10W)

get_gain_db(elevation: float) float[source]

Get vertical monopole gain at specified elevation.

Parameters:

elevation – Elevation angle in radians

Returns:

Antenna gain in dBi

class dvoacap.antenna_gain.InvertedVDipole(low_frequency: float, high_frequency: float, tx_power_dbw: float = 1.0)[source]

Bases: AntennaModel

Inverted 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.

__init__(low_frequency: float, high_frequency: float, tx_power_dbw: float = 1.0) None[source]

Initialize inverted V dipole antenna.

Parameters:
  • low_frequency – Lower frequency limit in MHz

  • high_frequency – Upper frequency limit in MHz

  • tx_power_dbw – Transmit power in dBW (default: 1 = 10W)

get_gain_db(elevation: float) float[source]

Get inverted V dipole gain at specified elevation.

Parameters:

elevation – Elevation angle in radians

Returns:

Antenna gain in dBi

class dvoacap.antenna_gain.ThreeElementYagi(low_frequency: float, high_frequency: float, tx_power_dbw: float = 1.0)[source]

Bases: AntennaModel

3-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.

__init__(low_frequency: float, high_frequency: float, tx_power_dbw: float = 1.0) None[source]

Initialize 3-element Yagi antenna.

Parameters:
  • low_frequency – Lower frequency limit in MHz

  • high_frequency – Upper frequency limit in MHz

  • tx_power_dbw – Transmit power in dBW (default: 1 = 10W)

get_gain_db(elevation: float) float[source]

Get 3-element Yagi gain at specified elevation.

Parameters:

elevation – Elevation angle in radians

Returns:

Antenna gain in dBi

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: Enum

Ionospheric layer types.

E = 0
F1 = 1
F2 = 2
class dvoacap.prediction_engine.PredictionMethod(value)[source]

Bases: Enum

Method 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: object

Complete signal information for a propagation mode.

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
__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: object

Information about a single propagation mode.

reflection: Reflection
signal: SignalInfo
hop_distance: float = 0.0
hop_count: int = 0
layer: IonosphericLayer = 2
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
__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: object

Complete propagation prediction for one frequency.

method: PredictionMethod = 'short'
mode_tx: IonosphericLayer = 2
mode_rx: IonosphericLayer = 2
hop_count: int = 0
tx_elevation: float = 0.0
rx_elevation: float = 0.0
virt_height: float = 0.0
signal: SignalInfo
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
get_mode_name(distance_rad: float) str[source]

Get mode name string (e.g., ‘2F2’, ‘F2F1’).

__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: object

VOACAP input parameters.

ssn: float = 100.0
month: int = 1
tx_location: GeoPoint
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
__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: object

Complete 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])
__init__()[source]

Initialize prediction engine.

predict(rx_location: GeoPoint, utc_time: float, frequencies: list[float]) None[source]

Perform complete propagation prediction.

Parameters:
  • rx_location – Receiver location (lat/lon in radians)

  • utc_time – UTC time as fraction of day (0.0 to 1.0)

  • frequencies – List of frequencies to predict (MHz)

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: IntEnum

Types 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: IntEnum

Types 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: object

Fixed coefficient data structure.

This corresponds to the TFixedCoeff record in FrMaps.pas. Contains arrays used for computing fixed ionospheric maps.

__init__()[source]
load_from_arrays(fakp: ndarray, fakmap: ndarray, hmym: ndarray, fakabp: ndarray, abmap: ndarray) None[source]

Load coefficients from separate arrays

class dvoacap.voacap_parser.CoeffData[source]

Bases: object

Complete coefficient data for one month.

This corresponds to the data loaded by TFourierMaps.LoadCoeffResource() from the Coeff##.dat files.

__init__()[source]
class dvoacap.voacap_parser.F2Data[source]

Bases: object

F2 critical frequency coefficient data.

This corresponds to the data loaded from FOF2CCIR##.dat files.

__init__()[source]
class dvoacap.voacap_parser.VoacapParser[source]

Bases: object

Parser 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:
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:
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:
static get_data_summary(coeff_data: CoeffData) dict[str, Any][source]

Get a summary of the coefficient data for inspection.

Parameters:

coeff_data – CoeffData object

Returns:

Dictionary with summary information

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

dvoacap.voacap_parser.load_f2_file(filepath: str) F2Data[source]

Load a FOF2CCIR##.dat file.

Parameters:

filepath – Path to the F2 file

Returns:

F2Data object

dvoacap.voacap_parser.load_month(data_dir: str, month: int) tuple[CoeffData, F2Data][source]

Load monthly coefficient data.

Parameters:
  • data_dir – Directory containing DVoaData files

  • month – Month number (1-12)

Returns:

Tuple of (CoeffData, F2Data)