Fork de SPLAT! (John A. Magliacane, KD2BD, 2002-2014), bajo GPLv2 heredada del original. El núcleo de cálculo de propagación (ITWOM v3.0, Sid Shumate) se mantiene sin modificar en cpp/itwom3.0.cpp, llamado vía FFI. El resto del pipeline (lectura de formatos SPLAT!, reportes, mapas, KML, gnuplot) se reescribió en Rust, con paralelización nativa vía rayon reemplazando el paralelismo por múltiples procesos del original. Validado contra el corpus golden de SPLAT! con drift < 0.02 dB en cálculos ITWOM.
192 lines
6.8 KiB
Bash
Executable File
192 lines
6.8 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# Alias splat -> splat-rs (versión nueva)
|
||
alias splat='splat-rs'
|
||
shopt -s expand_aliases
|
||
|
||
# Detectar hilos disponibles del procesador
|
||
NUM_THREADS=$(nproc 2>/dev/null || grep -c ^processor /proc/cpuinfo 2>/dev/null || echo 2)
|
||
echo "=== SPLAT paralelo | Hilos detectados: $NUM_THREADS | Alias: splat -> splat-rs ==="
|
||
|
||
ruta="."
|
||
|
||
# Copiar archivos base del proyecto
|
||
cp "$HOME/.splat-gui/projects/$1/prediccion/tx_sitepred.qth" "$ruta/txprofile.qth"
|
||
cp "$HOME/.splat-gui/projects/$1/prediccion/splat.lrp" "$ruta/splat.lrp"
|
||
|
||
# Constantes de desplazamiento
|
||
dezp=0.53965407
|
||
dezpj=$(echo "scale=8; $dezp/12" | bc)
|
||
dezp=0
|
||
|
||
# Leer y convertir coordenadas TX a decimal
|
||
tx_sitepred=$(sed -n 1p "$ruta/txprofile.qth" | sed 's/ /_/g')
|
||
lat=$(sed -n 2p "$ruta/txprofile.qth")
|
||
lon=$(sed -n 3p "$ruta/txprofile.qth")
|
||
|
||
lat_gradopred=$(echo "$lat" | awk '{print $1}')
|
||
lat_minutopred=$(echo "$lat" | awk '{print $2}')
|
||
lat_segundopred=$(echo "$lat" | awk '{print $3}')
|
||
lattx=$(echo "scale=8; $lat_gradopred + $lat_minutopred/60 + $lat_segundopred/3600" | bc)
|
||
|
||
long_gradopred=$(echo "$lon" | awk '{print $1}')
|
||
long_minutopred=$(echo "$lon" | awk '{print $2}')
|
||
long_segundopred=$(echo "$lon" | awk '{print $3}')
|
||
longtx=$(echo "scale=8; $long_gradopred + $long_minutopred/60 + $long_segundopred/3600" | bc)
|
||
|
||
# Reescribir txprofile en formato decimal puro
|
||
echo "$tx_sitepred" > "$ruta/txprofile.qth"
|
||
echo "$lattx" >> "$ruta/txprofile.qth"
|
||
echo "$longtx" >> "$ruta/txprofile.qth"
|
||
echo "30 m" >> "$ruta/txprofile.qth"
|
||
|
||
# Constantes para direcciones diagonales
|
||
a=0.269827035
|
||
b=0.467354134
|
||
aj=$(echo "scale=8; $a/12" | bc)
|
||
bj=$(echo "scale=8; $b/12" | bc)
|
||
|
||
# === Sistema de progreso global ===
|
||
TOTAL_STEPS=168 # 12 perfiles × (13 atenuaciones + 1 imagen final)
|
||
PROGRESS_FILE=$(mktemp)
|
||
echo 0 > "$PROGRESS_FILE"
|
||
PROGRESS_LOCK="${PROGRESS_FILE}.lock"
|
||
touch "$PROGRESS_LOCK"
|
||
|
||
update_progress() {
|
||
local angulo=$1
|
||
local paso_local=$2
|
||
local total_local=14
|
||
|
||
(
|
||
flock -x 200
|
||
local current
|
||
current=$(cat "$PROGRESS_FILE")
|
||
current=$((current + 1))
|
||
echo "$current" > "$PROGRESS_FILE"
|
||
local pct_total pct_local
|
||
pct_total=$(echo "scale=1; $current * 100 / $TOTAL_STEPS" | bc)
|
||
pct_local=$(echo "scale=1; $paso_local * 100 / $total_local" | bc)
|
||
printf "\r[Total: %5s%% | Perfil %3s°: %5s%% (%2d/%2d)]" \
|
||
"$pct_total" "$angulo" "$pct_local" "$paso_local" "$total_local" >&2
|
||
) 200>"$PROGRESS_LOCK"
|
||
}
|
||
|
||
# === Función de procesamiento por perfil (ángulo) ===
|
||
procesar_perfil() {
|
||
local angulo=$1
|
||
local rxfile="${ruta}/rxprofile_${angulo}.qth"
|
||
local attnfile="${ruta}/atenuaciones${angulo}.ttxt"
|
||
local paso=0
|
||
|
||
echo "${angulo}º dBuVm" > "$attnfile"
|
||
|
||
local i=1
|
||
while [ $i -lt 19 ]; do
|
||
local latrx longrx
|
||
|
||
case $angulo in
|
||
0) latrx=$(echo "scale=8; $lattx+$dezpj*$i" | bc); longrx=$longtx ;;
|
||
180) latrx=$(echo "scale=8; $lattx-$dezpj*$i" | bc); longrx=$longtx ;;
|
||
90) latrx=$lattx; longrx=$(echo "scale=8; $longtx-$dezpj*$i" | bc) ;;
|
||
270) latrx=$lattx; longrx=$(echo "scale=8; $longtx+$dezpj*$i" | bc) ;;
|
||
30) latrx=$(echo "scale=8; $lattx+$bj*$i" | bc); longrx=$(echo "scale=8; $longtx-$aj*$i" | bc) ;;
|
||
60) latrx=$(echo "scale=8; $lattx+$aj*$i" | bc); longrx=$(echo "scale=8; $longtx-$bj*$i" | bc) ;;
|
||
120) latrx=$(echo "scale=8; $lattx-$aj*$i" | bc); longrx=$(echo "scale=8; $longtx-$bj*$i" | bc) ;;
|
||
150) latrx=$(echo "scale=8; $lattx-$bj*$i" | bc); longrx=$(echo "scale=8; $longtx-$aj*$i" | bc) ;;
|
||
210) latrx=$(echo "scale=8; $lattx-$bj*$i" | bc); longrx=$(echo "scale=8; $longtx+$aj*$i" | bc) ;;
|
||
240) latrx=$(echo "scale=8; $lattx-$aj*$i" | bc); longrx=$(echo "scale=8; $longtx+$bj*$i" | bc) ;;
|
||
300) latrx=$(echo "scale=8; $lattx+$aj*$i" | bc); longrx=$(echo "scale=8; $longtx+$bj*$i" | bc) ;;
|
||
330) latrx=$(echo "scale=8; $lattx+$bj*$i" | bc); longrx=$(echo "scale=8; $longtx+$aj*$i" | bc) ;;
|
||
esac
|
||
|
||
echo "perfil de ${angulo} grados" > "$rxfile"
|
||
echo "$latrx" >> "$rxfile"
|
||
echo "$longrx" >> "$rxfile"
|
||
echo "10 m" >> "$rxfile"
|
||
|
||
local dist=$((i*5))
|
||
if [[ $dist -le 40 || $dist -eq 50 || $dist -eq 60 || $dist -eq 70 || $dist -eq 80 || $dist -eq 90 ]]; then
|
||
case $angulo in
|
||
0)
|
||
timeout 10 splat -t "$ruta/txprofile.qth" -r "$rxfile" -d /opt/splat/sdf -olditm -metric -l "$ruta/attnprfl${angulo}.png"
|
||
;;
|
||
30)
|
||
timeout 10 splat -r "$rxfile" -t "$ruta/txprofile.qth" -d /opt/splat/sdf -olditm -metric -nf -l "$ruta/attnprfl${angulo}.png"
|
||
;;
|
||
*)
|
||
timeout 10 splat -r "$rxfile" -t "$ruta/txprofile.qth" -d /opt/splat/sdf -olditm -metric -l "$ruta/attnprfl${angulo}.png"
|
||
;;
|
||
esac
|
||
|
||
local attn
|
||
attn=$(cat "${tx_sitepred}-to-perfil_de_${angulo}_grados.txt" | grep "Field strength" | cut -d " " -f 8 | sed 's/\./,/g')
|
||
echo "$attn" >> "$attnfile"
|
||
|
||
paso=$((paso + 1))
|
||
update_progress "$angulo" "$paso"
|
||
fi
|
||
|
||
i=$((i + 1))
|
||
done
|
||
|
||
# Imagen de perfil final (mismas inversiones TX/RX que el original)
|
||
case $angulo in
|
||
0)
|
||
splat -r "$ruta/txprofile.qth" -t "$rxfile" -d /opt/splat/sdf -olditm -metric -n -H "$ruta/perfil${angulo}.png"
|
||
;;
|
||
*)
|
||
splat -t "$rxfile" -r "$ruta/txprofile.qth" -d /opt/splat/sdf -olditm -metric -n -H "$ruta/perfil${angulo}.png"
|
||
;;
|
||
esac
|
||
|
||
paso=$((paso + 1))
|
||
update_progress "$angulo" "$paso"
|
||
|
||
# Limpiar archivo temporal de receptor
|
||
rm -f "$rxfile"
|
||
}
|
||
|
||
# === Lanzamiento paralelo controlado ===
|
||
ANGULOS=(0 30 60 90 120 150 180 210 240 270 300 330)
|
||
PIDS=()
|
||
|
||
for angulo in "${ANGULOS[@]}"; do
|
||
# Limpiar PIDs que ya terminaron
|
||
new_pids=()
|
||
for pid in "${PIDS[@]}"; do
|
||
kill -0 "$pid" 2>/dev/null && new_pids+=("$pid")
|
||
done
|
||
PIDS=("${new_pids[@]}")
|
||
|
||
# Respetar límite de hilos
|
||
while [ ${#PIDS[@]} -ge "$NUM_THREADS" ]; do
|
||
sleep 0.3
|
||
new_pids=()
|
||
for pid in "${PIDS[@]}"; do
|
||
kill -0 "$pid" 2>/dev/null && new_pids+=("$pid")
|
||
done
|
||
PIDS=("${new_pids[@]}")
|
||
done
|
||
|
||
procesar_perfil "$angulo" &
|
||
PIDS+=($!)
|
||
done
|
||
|
||
# Esperar a que terminen todos los trabajos
|
||
for pid in "${PIDS[@]}"; do
|
||
wait "$pid" 2>/dev/null
|
||
done
|
||
echo "" >&2
|
||
|
||
# === Concatenación final en orden ===
|
||
cat "$ruta/atenuaciones0.ttxt" > "$ruta/atenuaciones.ttxt"
|
||
for angulo in 30 60 90 120 150 180 210 240 270 300 330; do
|
||
cat "$ruta/atenuaciones${angulo}.ttxt" >> "$ruta/atenuaciones.ttxt"
|
||
done
|
||
|
||
# Limpieza de temporales de progreso
|
||
rm -f "$PROGRESS_FILE" "$PROGRESS_LOCK"
|
||
|
||
echo "=== Proceso completado. Resultados en atenuaciones.ttxt y perfil*.png ==="
|