Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 43 additions & 2 deletions src/dvoacap/prediction_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@

import numpy as np
from typing import List, Optional, Tuple
from dataclasses import dataclass, field
from dataclasses import dataclass, field, replace
from enum import Enum
from copy import deepcopy

from .path_geometry import PathGeometry, GeoPoint
from .geomagnetic import GeomagneticField
Expand Down Expand Up @@ -766,7 +767,11 @@ def _compute_signal(self, mode: ModeInfo, frequency: float):
xmuf = muf_info.ref.vert_freq * sec
xls = calc_muf_prob(frequency, xmuf, muf_info.muf, muf_info.sig_lo, muf_info.sig_hi)
xls = -self._to_db(max(1e-6, xls)) * sec
if debug_loss:
print(f"XLS additional loss: {xls:.2f} dB × {hop_count} hops = {hop_count * xls:.2f} dB", file=sys.stderr)
mode.signal.total_loss_db += hop_count * xls
if debug_loss:
print(f"FINAL TOTAL LOSS: {mode.signal.total_loss_db:.2f} dB", file=sys.stderr)

# Deciles
cpr = muf_info.ref.vert_freq / muf_info.muf
Expand Down Expand Up @@ -798,6 +803,14 @@ def _compute_signal(self, mode: ModeInfo, frequency: float):

# SNR
mode.signal.snr_db = mode.signal.power_dbw - self.noise_model.combined
if debug_loss:
print(f"TX power: {self.tx_antennas.current_antenna.tx_power_dbw:.2f} dBW", file=sys.stderr)
print(f"Signal power BEFORE field strength calc: {mode.signal.power_dbw:.2f} dBW", file=sys.stderr)
print(f"Field strength: {mode.signal.field_dbuv:.2f} dBµV/m", file=sys.stderr)
print(f"Signal power AFTER field strength calc: {mode.signal.power_dbw:.2f} dBW", file=sys.stderr)
print(f"Noise power: {self.noise_model.combined:.2f} dBW", file=sys.stderr)
print(f"SNR: {mode.signal.snr_db:.2f} dB", file=sys.stderr)
print("=" * 50, file=sys.stderr)

def _analyze_reliability(self, frequency: float) -> Prediction:
"""Analyze reliability and select best mode."""
Expand All @@ -806,6 +819,14 @@ def _analyze_reliability(self, frequency: float) -> Prediction:
if not self._modes:
return prediction

# Debug: Print mode powers at start
import sys
if False: # Enable for debugging
print(f"\n=== MODES AT START OF _analyze_reliability ===", file=sys.stderr)
for i, mode in enumerate(self._modes):
print(f"Mode {i}: power={mode.signal.power_dbw:.2f} dBW, snr={mode.signal.snr_db:.2f} dB", file=sys.stderr)
print("=" * 50, file=sys.stderr)

# Calculate reliability for each mode
for mode in self._modes:
if mode.ref.virt_height <= 70:
Expand All @@ -820,18 +841,38 @@ def _analyze_reliability(self, frequency: float) -> Prediction:
prediction.tx_elevation = self._best_mode.ref.elevation
prediction.virt_height = self._best_mode.ref.virt_height
prediction.hop_count = self._best_mode.hop_cnt
prediction.signal = self._best_mode.signal
# IMPORTANT: Deep copy the signal to avoid modifying best_mode.signal when combining modes
prediction.signal = deepcopy(self._best_mode.signal)
prediction.noise_dbw = self.noise_model.combined_noise.value.median
prediction.mode_tx = self._best_mode.layer

if False: # Debug
print(f"\n=== AFTER BEST MODE SELECTION ===", file=sys.stderr)
print(f"Best mode power: {self._best_mode.signal.power_dbw:.2f} dBW", file=sys.stderr)
print(f"Best mode SNR: {self._best_mode.signal.snr_db:.2f} dB", file=sys.stderr)
print(f"Prediction power (before sum): {prediction.signal.power_dbw:.2f} dBW", file=sys.stderr)
print(f"Prediction SNR (before sum): {prediction.signal.snr_db:.2f} dB", file=sys.stderr)
print("=" * 50, file=sys.stderr)

# Add signals from all modes (random phase)
if len(self._modes) > 1:
self._calc_sum_of_modes(prediction)
if False: # Debug
print(f"\n=== AFTER _calc_sum_of_modes ===", file=sys.stderr)
print(f"Prediction power (after sum): {prediction.signal.power_dbw:.2f} dBW", file=sys.stderr)
print(f"Prediction SNR (before recalc): {prediction.signal.snr_db:.2f} dB", file=sys.stderr)
print(f"About to recalculate SNR...", file=sys.stderr)
print("=" * 50, file=sys.stderr)
prediction.signal.snr_db = (
self._best_mode.signal.snr_db +
prediction.signal.power_dbw -
self._best_mode.signal.power_dbw
)
if False: # Debug
print(f"\n=== AFTER SNR RECALC ===", file=sys.stderr)
print(f"Prediction SNR (after recalc): {prediction.signal.snr_db:.2f} dB", file=sys.stderr)
print(f"Calculation: {self._best_mode.signal.snr_db:.2f} + {prediction.signal.power_dbw:.2f} - {self._best_mode.signal.power_dbw:.2f} = {prediction.signal.snr_db:.2f}", file=sys.stderr)
print("=" * 50, file=sys.stderr)
self._calc_reliability(prediction.signal, clamp=True)

# Required power for specified reliability
Expand Down