Files
cescobar 9d7d3bac45 Commit inicial: splat-rs — fork/port a Rust de SPLAT!
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.
2026-08-23 01:50:41 -05:00

192 lines
6.8 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 ==="