diff --git a/overlay/etc/skel/.local/share/emcomm-tools/voacap/et-voacap.sh b/overlay/etc/skel/.local/share/emcomm-tools/voacap/et-voacap.sh new file mode 100755 index 0000000..d66609d --- /dev/null +++ b/overlay/etc/skel/.local/share/emcomm-tools/voacap/et-voacap.sh @@ -0,0 +1,140 @@ +#!/bin/bash +# +# Author : Gaston Gonzalez +# Date : 23 May 2023 +# Updated : 16 August 2025 +# Purpose : Offline HF prediction using voacapl + +if [[ $# -ne 4 ]]; then + echo "Usage $(basename $0) " + echo " Callsign of transmitting station" + echo " Callsign of receiving station" + echo " Output power [5|100|500|1500]" + echo " Mode [AM|CW|FT8|SSB]" + exit 1 +fi + +ET_SSN="${HOME}/.local/share/emcomm-tools/voacap/ssn.txt" +if [[ ! -e ${ET_SSN} ]]; then + "Sunspot numbers not available: ${ET_SSN}. Exiting" + exit 1 +fi + +ET_VOA_WORKING_DIR=$HOME/itshfbc/run +ET_VOA_REPORT=${ET_VOA_WORKING_DIR}/voacapl.txt +INP=${ET_VOA_WORKING_DIR}/voacapx.dat +OUT=${ET_VOA_WORKING_DIR}/voacapx.out + +# Year = 2023 +YEAR=$(echo $(date '+%Y')) + +# Month (May) = 5.00 +MONTH=$(date +'%m') +MONTH_FMT=$(date +'%-m.00') + +####################################################################### +# TX Antenna +####################################################################### + +TX_STATION=$1 +TX_JSON=tx-station.json +curl -f -s http://localhost:1981/api/license?callsign=$TX_STATION > $TX_JSON +TL=$(cat $TX_JSON | jq .lat) +TK=$(cat $TX_JSON | jq .lon) + +TL1=$( awk -v n1=$TL -v n2=90 -v n3=-90 'BEGIN {if (n1n2) printf ("%s", "a"); else printf ("%.2f", n1);}' ) + +# add North or South (N/S) +TLA=$( awk -v n1=$TL1 -v n2=0 'BEGIN {if (n1n2) printf ("%s", "a"); else printf ("%.2f", n1);}' ) + +# add East or West (E/W) +TLO=$( awk -v n1=$TK1 -v n2=0 'BEGIN {if (n1 $RX_JSON +RL=$(cat $RX_JSON | jq .lat) +RK=$(cat $RX_JSON | jq .lon) + +echo "RX ($RX_STATION): $RL,$RK" +RL1=$( awk -v n1=$RL -v n2=90 -v n3=-90 'BEGIN {if (n1n2) printf ("%s", "a"); else printf ("%.2f", n1);}' ) + +# add North or South +RLA=$( awk -v n1=$RL1 -v n2=0 'BEGIN {if (n1n2) printf ("%s", "a"); else printf ("%.2f", n1);}' ) + +# add East or West +RLO=$( awk -v n1=$RK1 -v n2=0 'BEGIN {if (n1. (117.) +ssn=`grep "$YEAR $MONTH" ${ET_SSN} | awk '{print $5}' | cut -d"." -f1` + +# read more about fine-tuning your input file: +# http://www.voacap.com/voacapw.html +# http://www.voacap.com/frequency.html + +echo -e "\n" + +cat << END | tee $INP +LINEMAX 999 number of lines-per-page +COEFFS CCIR +TIME 1 24 1 1 +MONTH $YEAR $MONTH_FMT +SUNSPOT $ssn. +LABEL $TX$RX +CIRCUIT $TLA $TLO $RLA $RLO S 0 +SYSTEM 1. 155. 3.00 90. $MD 3.00 0.10 +FPROB 1.00 1.00 1.00 0.00 +ANTENNA 1 1 2 30 0.000[samples/sample.00 ] 0.0 $PW +ANTENNA 2 2 2 30 0.000[samples/sample.00 ] 0.0 0.0000 +FREQUENCY 3.60 5.30 7.1010.1014.1018.1021.1024.9028.20 0.00 0.00 +METHOD 30 0 +BOTLINES 8 12 21 +TOPLINES 1 2 3 4 6 +EXECUTE +QUIT + +END + +voacapl -s ~/itshfbc +echo "voacapl exited with $? using in=$INP and out=$OUT" + +(tail -n +27 $OUT | head -n 5 && grep -e'- REL' $OUT && grep -e'- S DBW' $OUT) | ./rel.pl > ${ET_VOA_REPORT} +cat ${ET_VOA_REPORT} diff --git a/overlay/etc/skel/.local/share/emcomm-tools/voacap/fetch-ssn.sh b/overlay/etc/skel/.local/share/emcomm-tools/voacap/fetch-ssn.sh new file mode 100755 index 0000000..f0b84c9 --- /dev/null +++ b/overlay/etc/skel/.local/share/emcomm-tools/voacap/fetch-ssn.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Author : Gaston Gonzalez +# Date : 16 August 2025 +# Purpose : Fetch SSNs for VOACAP prediction + +source /opt/emcomm-tools/bin/et-common + +FILE="ssn.txt" +URL="https://www.sidc.be/silso/FORECASTS/prediML.txt" +curl -s -f -L -o ${FILE} ${URL} + +if [[ $? -ne 0 ]]; then + echo -e "${RED}Failed to update ${FILE} from: ${URL}." + exit 1 +fi diff --git a/overlay/etc/skel/.local/share/emcomm-tools/voacap/rel.pl b/overlay/etc/skel/.local/share/emcomm-tools/voacap/rel.pl new file mode 100755 index 0000000..6448585 --- /dev/null +++ b/overlay/etc/skel/.local/share/emcomm-tools/voacap/rel.pl @@ -0,0 +1,133 @@ +#!/usr/bin/perl +# Author: Jari Perkiömäki OH6BG +# 12 June 2016: initial release +# 18 June 2016: added Long-Path predictions; use unpack for extracting table data +# 18 June 2016: added Power, Mode; small improvements +# + +use strict; +use warnings; + +my @relhour = (); +my @sdbwhour = (); +my @co = (); +my @mo = (); +my @pwr = (); +my @db = (); +my $km = 0; +my $mi = 0; +my $brn = 0; +my $fh; +my $voa; +my $mode; +my $path = "Short-Path"; + +# main loop +open $fh, '>>', \$voa or die $!; +process (); +close $fh; +print $voa; +exit; + +### end ### + +sub process { + my $format = 'A4 A5 A5 A5 A5 A5 A5 A5 A5 A5'; + while (<>) { + + s/^\s+|\s+$//g; + + if ( substr ($_, -1) eq "s" ) { @mo = split /\s+/; } + + elsif ( substr ($_, -2) eq "kW" ) { @pwr = split /\s+/; } + elsif ( substr ($_, -2) eq "dB" ) { + + @db = split /\s+/; + if ( $db[13] eq "24.0" ) { $mode = "CW"; } + elsif ( $db[13] eq "38.0" ) { $mode = "SSB"; } + else { $mode = "AM"; } + + } + + elsif ( /Long/ ) { $path = "Long-Path"; } + + elsif ( substr ($_, -1) =~ /\d/ ) { + + @co = split /\s+/; + $brn = sprintf "%d", $co[9] + 0.5; + $km = sprintf "%d", $co[12] + 0.5; + $mi = sprintf "%d", ($co[12] * 0.62137) + 0.5; + + } + + elsif ( substr ($_, -3) eq "REL" ) { push (@relhour, [ unpack( $format, $_ ) ] ); } + elsif ( substr ($_, -3) eq "DBW" ) { push (@sdbwhour,[ unpack( $format, $_ ) ] ); } + + } # while + + for ($fh) { + print $_ "VOACAP Prediction via $path. $mo[0] $mo[1]: SSN $mo[4] Power = $pwr[$#pwr], $mode\n"; + print $_ "TX ($co[0]$co[1], $co[2]$co[3]) to RX ($co[5]$co[6], $co[7]$co[8]): $km km, $mi mi, $brn deg\n\n"; + print $_ " | 01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|\n"; + } + + foreach my $freq (reverse 1..9) { + print $fh band($freq) . "|"; + foreach my $h (0..23) { print $fh makehourfreq( $h, $freq ); } + print $fh "|" . band($freq) . "\n"; + } + + for ($fh) { + print $_ " | 01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|\n\n"; + print $_ "A = 90 - 100% d = 25 - 49% * = REL 0%, but Signal Power over Noise\n"; + print $_ "B = 75 - 89% e = 10 - 24%\n"; + print $_ "C = 50 - 74% f = 1 - 9%\n\n"; + } + + @relhour = (); + @sdbwhour = (); + + } # process + +sub makehourfreq { + + my $h = $_[0]; + my $f = $_[1]; + my $r = $relhour[$h][$f]; + my $s = $sdbwhour[$h][$f]; + + if ( ($r == 0.00 && $s >= -167) ) { return " * "; } + else { return col($relhour[$h][$f]); } + + } + +sub band { + + my $b = $_[0]; + + if ($b == 1) { return "80"; } + if ($b == 2) { return "60"; } + if ($b == 3) { return "40"; } + if ($b == 4) { return "30"; } + if ($b == 5) { return "20"; } + if ($b == 6) { return "17"; } + if ($b == 7) { return "15"; } + if ($b == 8) { return "12"; } + if ($b == 9) { return "10"; } + + } + +sub col { + + my $rel = $_[0]; + + if ($rel == 0.00 ) { return " "; } + elsif ($rel >= 0.01 && $rel < 0.10 ) { return " f "; } + elsif ($rel >= 0.10 && $rel < 0.25 ) { return " e "; } + elsif ($rel >= 0.25 && $rel < 0.50 ) { return " d "; } + elsif ($rel >= 0.50 && $rel < 0.75 ) { return " C "; } + elsif ($rel >= 0.75 && $rel < 0.90 ) { return " B "; } + elsif ($rel >= 0.90 && $rel < 1.01 ) { return " A "; } + else { return " - "; } + + } \ No newline at end of file diff --git a/overlay/etc/skel/.local/share/emcomm-tools/voacap/ssn.txt b/overlay/etc/skel/.local/share/emcomm-tools/voacap/ssn.txt new file mode 100644 index 0000000..d7fd966 --- /dev/null +++ b/overlay/etc/skel/.local/share/emcomm-tools/voacap/ssn.txt @@ -0,0 +1,18 @@ +2025 02 2025.122 : 145.4 5.0 +2025 03 2025.204 : 145.5 10.2 +2025 04 2025.286 : 145.0 15.5 +2025 05 2025.371 : 143.1 20.7 +2025 06 2025.453 : 140.9 24.6 +2025 07 2025.538 : 137.3 26.5 +2025 08 2025.623 : 133.1 27.0 +2025 09 2025.705 : 129.4 27.3 +2025 10 2025.790 : 126.1 29.0 +2025 11 2025.873 : 123.2 30.0 +2025 12 2025.958 : 120.8 29.3 +2026 01 2026.042 : 118.0 28.2 +2026 02 2026.122 : 114.6 27.4 +2026 03 2026.204 : 110.4 25.8 +2026 04 2026.286 : 106.1 24.6 +2026 05 2026.371 : 102.1 23.8 +2026 06 2026.453 : 97.8 23.9 +2026 07 2026.538 : 94.0 25.1