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

19 KiB
Raw Permalink Blame History

splat-rs — Manual del Usuario

splat-rs es un port en Rust de SPLAT! (Signal Propagation, Loss, And Terrain analysis tool) con paralelización nativa, salidas en español y una nueva funcionalidad de tabla de intensidad de campo.

Compatible con los formatos .qth, .lrp, .az, .el, .udt, .cities y .sdf[.bz2] del SPLAT! 1.4.x original. Validado contra el corpus golden de SPLAT! con drift inferior a 0.02 dB en cálculos ITWOM.


1. Inicio rápido

# Análisis de enlace TX → RX
splat-rs -t txenlace.qth -r rxenlace.qth -d sdf/

# Cobertura completa de un sitio
splat-rs -t tx_site.qth -d sdf/ -L 10 -R 80

# Tabla de intensidad de campo (alternativa al script perfiles.sh)
splat-rs -t tx_site.qth -d sdf/ --sft atenuaciones.txt --sft-max-km 150

Salidas en --out-dir (default: directorio actual):

Archivo Cuándo se genera
<TX>-site_report.txt si no hay -r
<TX>-to-<RX>.txt si hay -r (path report)
coverage.ppm/.png/.kml si no está --no-map
<archivo>.txt + .csv si está --sft <archivo>
splat.gp + *.gp si está -h/-H/-p/-e/-l <archivo>

2. Construcción

cd splat-rs
cargo build --release
# Binario: ./target/release/splat-rs

Requiere:

  • Rust ≥ 1.80 (probado con 1.92)
  • libbz2.so accesible (sistema o miniconda)
  • gnuplot (opcional, para renderizar los .gp)
  • convert de ImageMagick (opcional, para PPM → PNG transparente)

Para ejecutar con libbz2 desde miniconda:

LD_LIBRARY_PATH=$HOME/miniconda3/lib ./target/release/splat-rs ...

3. Formatos de entrada

.qth — Sitio (TX o RX)

Cuatro líneas:

Nombre del sitio
-1 -01 -23.54        ; latitud (DMS o decimal)
79 27 31.21          ; longitud (DMS o decimal, positiva = oeste)
14 m                 ; altura antena AGL (metros con 'm', si no = pies)

.lrp — Parámetros Longley-Rice

Una constante numérica por línea, comentarios con ;:

15.000   ; Constante dieléctrica de la Tierra
0.005    ; Conductividad (S/m)
301.00   ; Refracción atmosférica (N-units)
426      ; Frecuencia (MHz)
5        ; Clima radioeléctrico (1-7)
1        ; Polarización (0=H, 1=V)
0.50     ; Fracción de situaciones
0.50     ; Fracción de tiempo
2000     ; ERP en watts (línea 9, opcional)

Climas: 1=Ecuatorial, 2=Subtropical Continental, 3=Subtropical Marítimo, 4=Desértico, 5=Templado Continental, 6=Templado Marítimo (tierra), 7=Templado Marítimo (mar).

.az — Patrón azimutal de antena (autodetectado al lado del .qth del TX)

345.0           ; rotación en grados (clockwise desde el norte verdadero)
0    0.49       ; az amplitud (0..1)
1    0.50
2    0.51
...

.el — Patrón vertical de antena

8.0  345.0      ; tilt mecánico, azimuth del tilt
-10   0.04
-9.5  0.06
...

Usa --no-pattern para ignorar archivos .az/.el aun si existen.

.udt — Terreno definido por usuario

CSV de obstáculos puntuales:

; Edificios y antenas en Quevedo
-1.0250, 79.4587, 50 m
-1.0260, 79.4590, 80 m

Cada feature se "pinta" en un radio de ~5 píxeles (~465 m a 1200 ppd) sobre el DEM. El máximo entre la base SDF y el UDT prevalece.

.cities o -s <file> — Sitios de interés

CSV name, lat, lon:

Quito, -0.18, 78.47
Guayaquil, -2 10 0, 79 53 0

.sdf[.bz2] — Datos de elevación digital

Archivos SPLAT! estándar. Nombres minlat:maxlat:minlon:maxlon.sdf.bz2 cubriendo 1° × 1° cada uno. Carpeta vía -d sdf/. Soporta tanto 3 arc-sec (1200 ppd) como 1 arc-sec (3600 ppd, modo HD).


4. Referencia de banderas

Entrada

Bandera Descripción
-t, --tx FILE TX .qth (obligatorio)
-r, --rx FILE RX .qth (opcional; si está → path report; si no → site report)
-d, --sdf DIR Directorio con tiles .sdf[.bz2] (obligatorio)
--lrp FILE .lrp (default: splat.lrp junto al TX)
--erp WATTS Override del ERP del .lrp
-s, --cities FILE Archivo de sitios; repetible
--udt FILE Terreno definido por usuario; repetible

Modelo y geometría

Bandera Descripción Default
--olditm Usa Longley-Rice clásico en vez de ITWOM v3.0 off (ITWOM)
-L, --rx-altitude-m M Altura RX AGL para sweep de cobertura 10 m
-R, --range-km KM Radio de cobertura 40 km
--metric Unidades métricas en reportes true
--gc M Altura de clutter (obstáculos urbanos) 0
--fz F Clearance Fresnel (F ∈ [0,1]) 0.6 (60%)
--no-pattern Ignora .az/.el autodetectados off

Salidas — gráficas (cada una toma un nombre de archivo)

Bandera Genera Equivale a SPLAT
-h FILE Gráfico de alturas (perfil + LOS + curvatura + Fresnel) -h
-H FILE Versión normalizada del anterior -H
-p FILE Perfil del terreno (elevación vs distancia) -p
-e FILE Perfil de ángulo de elevación -e
-l FILE Gráfico de pérdida del trayecto -l
--plot-format FMT Tipo de salida gnuplot (png, svg, ps...)

Convención -h/-H: el plot de alturas usa el marco de tierra aplanada (4/3): el perfil del terreno se eleva por d·(D-d)/(2·R') para que la LOS sea una recta y la zona de Fresnel se dibuje como su geometría natural debajo. Si el terreno aparente toca la Fresnel en el gráfico, es una obstrucción real — convención estándar en ingeniería de RF (ATDI, Pathloss, etc.). Además se superpone una referencia de curvatura (parábola en el mismo eje Y, anclada al fondo del plot) cuyo peak coincide con el terreno más bajo y endpoints sit en min(terreno)max_drop. La magnitud del hump es D²/(8·R'): ~150 m para D=100 km, ~180 m para D=110 km. Si quieres ver el perfil geográfico crudo (sin corrección de curvatura), usa -p.

Auto-render: si gnuplot está en el PATH, splat-rs lo invoca automáticamente tras escribir los .gp y produce directamente el PNG/SVG/PS. Cada flag escribe a su propio subdirectorio (h-<stem>/, p-<stem>/, etc.) para que no colisionen al pedir varios plots a la vez:

splat-rs -t tx.qth -r rx.qth -d sdf/ --no-map \
  -h alturas.png -p terreno.png -e elevacion.png
# → out_dir/h-alturas/alturas.png
# → out_dir/p-terreno/terreno.png
# → out_dir/e-elevacion/elevacion.png

Si no hay gnuplot, splat-rs deja los .gp para que el usuario los renderice manualmente (cd subdir && gnuplot splat.gp).

Salidas — mapa de cobertura (sweep 360°)

Bandera Descripción
-c, --los-coverage Modo LOS (sin ITWOM, ~75× más rápido)
--no-map No generar mapa (solo reporte)
--no-kml No generar KML
--no-link-line Omitir línea TX→RX en KML
--max-loss-db DB Umbral de pérdida (mayor → blanco transparente). FM: 110-120, UHF: 125-135, microondas: 160+
--min-loss-db DB Pérdida mínima (mapea al color más fuerte)

Leyenda automática: cada vez que se genera un mapa de cobertura, splat-rs también escribe legend.svg (con texto) y legend.ppm (barra de colores sola) que muestran el mapeo color↔pérdida↔intensidad de campo del run.

Tabla de intensidad de campo (-sft)

Bandera Descripción
--sft FILE Genera tabla en <FILE> (texto) y <FILE>.csv
--sft-max-km KM Extiende a KM (default 90; pasos de 10 km después de 90)
--sft-azimuths LISTA Azimuts custom CSV (default: 0,30,60,...,330)
--sft-distances LISTA Distancias custom CSV (override total)

Sistema

Bandera Descripción Default
--threads N Hilos para rayon (0 = todos los cores) 0
--out-dir DIR Directorio de salida .
--help Ayuda completa
-V, --version Versión

5. Flujos de trabajo comunes

5.1 Análisis rápido de sitio (qué tan elevada está la antena vs el terreno)

splat-rs -t mi_sitio.qth -d sdf/ --no-map

Genera mi_sitio-site_report.txt con: ubicación, elevación del terreno, altura de la antena, HAAT (altura sobre terreno promedio según FCC Part 73.313(d)) y promedios de terreno en 8 azimuts cardinales.

5.2 Estudio de enlace punto-a-punto

splat-rs -t tx.qth -r rx.qth -d sdf/ --no-map -h alturas.png

Genera:

  • Path report en español con pérdida ITWOM, modo de propagación, análisis de obstrucciones y zonas de Fresnel
  • alturas.png (vía gnuplot splat.gp) con perfil + LOS + curvatura 4/3 + Fresnel del 60% y 100%

5.3 Mapa de cobertura ITWOM completo (lento pero preciso)

splat-rs -t tx.qth -d sdf/ -L 10 -R 80 \
         --max-loss-db 120 \
         -s ciudades.cities --out-dir cobertura/

Genera en cobertura/:

  • coverage.ppm (raster PPM puro)
  • coverage.png (con blanco → transparente)
  • coverage.kml (Google Earth con TX, ciudades y línea de enlace)
  • <TX>-site_report.txt

Tiempo típico: ~2-4 min en 16 cores para 80 km de radio.

5.4 Mapa LOS rápido (bosquejo previo)

splat-rs -t tx.qth -d sdf/ -L 10 -R 80 -c

Mismo formato de salidas pero ~75× más rápido (sin llamadas a ITWOM). Útil para identificar primero qué zonas tienen línea de vista antes de hacer el sweep ITWOM completo. Tiempo típico: 1-3 s.

5.5 Tabla de intensidad de campo (alternativa a perfiles.sh)

Default: 12 azimuts × 13 distancias (540 km en pasos de 5, luego 50/60/70/80/90):

splat-rs -t tx.qth -d sdf/ --olditm --no-map --sft atenuaciones.txt

Extendida hasta 150 km:

splat-rs -t tx.qth -d sdf/ --olditm --no-map \
         --sft atenuaciones.txt --sft-max-km 150

Grid completamente personalizado (8 cardinales × distancias específicas):

splat-rs -t tx.qth -d sdf/ --olditm --no-map \
         --sft puntos.txt \
         --sft-azimuths 0,45,90,135,180,225,270,315 \
         --sft-distances 1,2,5,10,20,50,100,150,200

Salida en atenuaciones.txt:

# Tabla de intensidad de campo (dBµV/m) — splat-rs
# TX: Cerro Cochabamba @ (-1.6986, 79.1072), 91.5 MHz, ERP 2000 W, modelo LongleyRice

   Dist/Az      0°     30°     60°     90°    120°    ...
      5 km   95.08   69.96   43.30   35.89   35.82   ...
     10 km   24.62   47.60   30.73   33.41   13.03   ...
     ...

Y CSV atenuaciones.csv para Excel/LibreOffice. Si necesitas decimal coma para es_EC:

sed 's/\./,/g' atenuaciones.csv > atenuaciones-es.csv

Tiempo típico: <10 ms por tabla (compute) más 6-7 s de carga SDF (una vez).

5.6 Estudio con patrón de antena directiva

Si junto al .qth del TX están <base>.az y <base>.el, splat-rs los detecta automáticamente y aplica el patrón en la pérdida y la tabla SFT:

ls
# tx_site.qth  tx_site.az  tx_site.el  splat.lrp

splat-rs -t tx_site.qth -d sdf/ --sft tabla.txt
# stderr: "Patrón de antena cargado (rotación 345.0°, tilt 8.0°)"

El reporte incluye Patrón de antena de TX hacia RX: 0.562 (-5.00 dB) cuando hay -r.

5.7 Override de ERP para análisis A/B

splat-rs -t tx.qth -r rx.qth -d sdf/ --erp 2000 --no-map
splat-rs -t tx.qth -r rx.qth -d sdf/ --erp 5000 --no-map  # comparar

5.8 UDT — terreno con edificios sintéticos

cat > obstaculos.udt <<EOF
; Torre de transmisión vecina
-1.0245, 79.4593, 50 m
EOF

splat-rs -t tx.qth -r rx.qth -d sdf/ --udt obstaculos.udt --no-map

El reporte detectará obstrucciones en cada UDT y recomendará la altura mínima de antena RX para librar terreno y zonas de Fresnel.


6. Salidas explicadas

Path report (<TX>-to-<RX>.txt)

Bloques en orden:

  1. Sitio transmisor: nombre, ubicación DMS, elevación, altura antena, HAAT, distancia, azimut, ángulo elevación al RX
  2. Sitio receptor: idem desde el RX
  3. Parámetros del modelo: dieléctrica, conductividad, refracción, frecuencia, clima, polarización, fracciones, ERP/EIRP (si está en .lrp)
  4. Resumen del enlace: pérdida en espacio libre, pérdida ITWOM (o LR), atenuación por terreno, modo de propagación (LDV / horizonte simple / horizonte doble + difracción/troposcatter)
  5. Análisis de obstrucciones: lista de cada punto bloqueante y recomendaciones de altura para librar LOS / 60% Fresnel / Fresnel completa

Site report (<TX>-site_report.txt)

Cuando solo se da -t. Estructura:

  • Sitio (DMS), elevación del terreno, altura de la antena
  • HAAT (altura sobre promedio del terreno)
  • Promedio del terreno en 8 azimuts (0°, 45°, 90°, ..., 315°) entre 2 y 10 millas

Coverage map

  • coverage.ppm: raster PPM/P6, dimensiones automáticas según los radiales
  • coverage.png: misma imagen con convert -transparent white si está ImageMagick disponible
  • coverage.kml: Google Earth con GroundOverlay apuntando al PNG, línea amarilla TX→RX (si hay -r), Placemarks para TX/RX/ciudades
  • legend.svg: leyenda con barra de colores y dos ejes: pérdida en dB a la izquierda, intensidad de campo (dBµV/m) a la derecha. Calculada con la frecuencia y ERP del .lrp. Renderiza en cualquier navegador o se convierte con convert legend.svg legend.png.
  • legend.ppm: solo la barra de color (sin texto), 30×280 px. Útil para componer con el mapa via convert +append coverage.png legend.ppm composite.png o similar.

Tabla SFT

  • <archivo>: tabla de texto formateada con encabezado descriptivo
  • <archivo>.csv: para importar en hojas de cálculo

Gráficos gnuplot

Cada vez que se pide -h/-H/-p/-e/-l, se genera un set en el subdirectorio:

  • splat.gp: orquestador (set title/xlabel/ylabel + plot)
  • profile.gp: terreno
  • reference.gp: línea de vista
  • curvature.gp: curvatura 4/3 Tierra
  • fresnel.gp, fresnel_pt_6.gp: zonas de Fresnel (cuando aplica)

Para renderizar: cd subdir && gnuplot splat.gp produce el archivo de imagen.


7. Rendimiento

Hardware típico (16 cores)

Operación Tiempo
Carga 54 tiles SDF (Ecuador completo) 6-7 s
Path report TX↔RX (1 enlace) <1 s
Site report (HAAT + 8 radiales) <1 s
Tabla SFT 12×13 1-2 ms
Tabla SFT 12×19 (hasta 150 km) 2-3 ms
Mapa LOS coverage 80 km 1-3 s
Mapa ITWOM coverage 40 km 1-2 min
Mapa ITWOM coverage 80 km 3-5 min

Speedup típico paralelo / secuencial: 10-12× (eficiencia 65-75% de los 16 cores).

Comparación con SPLAT! original (single-thread)

SPLAT! v1.4.2 splat-rs
Mapa ITWOM 40 km ~25 min ~2 min (12.5× más rápido)
Tabla SFT (perfiles.sh) ~30 min ~7 s (260× más rápido)
Path report único ~2 s <1 s

8. Diagnóstico de problemas

"El TX (X, Y) no está cubierto por los tiles SDF de ..."

El TX cae fuera de los tiles cargados. Verifica los nombres de archivo en sdf/: deben tener formato minlat:maxlat:minlon:maxlon.sdf.bz2 y cubrir el rango de coordenadas del TX/RX.

Mapa de cobertura completamente blanco

--max-loss-db demasiado bajo para el escenario:

  • Microondas en LOS limpio: pérdida 100-130 dB → --max-loss-db 130 o más
  • Microondas con obstrucciones: hasta 180 dB → --max-loss-db 180

Patrón de antena no aplicado

splat-rs busca <base>.az y <base>.el donde <base> es el nombre del .qth sin extensión. Si tu antena se llama tx.qth, debe haber tx.az / tx.el en el mismo directorio. Verifica con --no-pattern para forzar isotrópica y comparar.

Aliasing radial visible en mapa de cobertura

Es inherente al método radial-sweep. Mitigaciones:

  • Subir umbral con --max-loss-db para mostrar solo cobertura útil
  • Usar HD mode (DEM 1 arc-sec, ppd=3600) — 9× más lento pero menos artifacts
  • El renderer ya aplica supercover 2×2 + dilatación; resta es físicamente irreducible

gnuplot: not found al pedir -h/-H/-p/-e/-l

splat-rs solo escribe los .gp data y orquestador. Para rasterizar necesitas gnuplot instalado:

sudo apt install gnuplot

Ejecución más lenta de lo esperado

Verifica que rayon esté usando todos los cores:

splat-rs ... 2>&1 | head -1
# "Hilos disponibles: 16 (de 16 lógicos)"

Si aparece menos, usa --threads N para forzar.


9. Diferencias con SPLAT! original

Mejoras

  • Reentrancia thread-safe: static → thread_local en ITWOM permite N hilos sin contención
  • Paralelización nativa: rayon distribuye radiales/SFT-celdas entre todos los cores
  • Carga DEM única: vs SPLAT que recarga en cada invocación
  • Salida en español (homologada por Charles)
  • Sintaxis CLI compatible + extensiones (--sft, --threads, --max-loss-db)
  • CSV de la tabla SFT además del texto
  • Mensajes de error útiles con contexto

No implementado

  • -ano / -ani: input/output alfanumérico (uso poco común)
  • -b: archivos de fronteras cartográficas (overlay PPM)
  • -dbm: paleta dBm en vez de dBµV/m (existe en código pero no expuesto en CLI)
  • -geo: archivo georreferencia Xastir (formato muy específico)
  • -log: registro del comando (uso >&2 redirect en shell)
  • -ngs: topografía gris como blanco (escala de grises)
  • -sc: contornos suaves (paleta lineal vs cuantizada)
  • -db: contornos por encima de un umbral
  • -nf: omitir Fresnel en height plot (siempre se grafica)

Drift numérico

  • ITWOM path loss: ±0.02 dB vs SPLAT golden (floating-point con -ffast-math activado en C++ original)
  • HAAT: ±0.1 m por sampling de los 8 radiales
  • Ángulos: bit-idénticos (mismo radio terrestre 20902230.97 ft)

10. Estructura del proyecto

splat-rs/
├── Cargo.toml
├── MANUAL.md                    # este archivo
├── build.rs                     # compila itwom + linkea libbz2
├── cpp/
│   ├── itwom3.0.cpp             # vendored, static→thread_local
│   └── itwom_ffi.cpp            # C ABI wrapper (refs → pointers)
└── src/
    ├── lib.rs                   # mod tree
    ├── itwom.rs                 # FFI seguro a ITWOM/Longley-Rice
    ├── sdf.rs                   # loader .sdf[.bz2] + DemTileSet indexado
    ├── qth.rs                   # parser .qth (DMS o decimal)
    ├── lrp.rs                   # parser .lrp (tolerante a prosa)
    ├── pat.rs                   # parser .az/.el + AntennaPattern
    ├── udt.rs                   # parser .udt + DemWithUdt overlay
    ├── cities.rs                # parser .cities
    ├── geo.rs                   # Distance, Azimuth, step_great_circle
    ├── radial.rs                # compute_radial + plot_lr_map_parallel
    ├── coverage.rs              # CoverageMap + rasterize_line + fill_holes
    ├── ppm.rs                   # writer PPM con paleta signal-strength
    ├── kml.rs                   # writer KML GroundOverlay + LineString
    ├── gnuplot.rs               # writers .gp (perfil/altura/elevación)
    ├── report.rs                # PathReport + SiteReport + ObstructionAnalysis
    ├── sft.rs                   # Strength Field Table (paralelo)
    ├── types.rs                 # Site, Config
    └── bin/
        ├── splat-rs.rs          # CLI principal
        └── bench.rs             # microbenchmark ser vs par

26 tests unitarios + 4 ignored (end-to-end con DEM real).


11. Créditos

  • SPLAT! original: John A. Magliacane, KD2BD (20022014)
  • ITWOM v3.0: Sid Shumate (2010)
  • Adaptación al español + variante 1.4.2-Charles: Ing. Charles Escobar
  • Port a Rust + paralelización: 2026

Bajo licencia GPLv2 (heredada del SPLAT! original).