# 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 ```bash # 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 | |---|---| | `-site_report.txt` | si **no** hay `-r` | | `-to-.txt` | si hay `-r` (path report) | | `coverage.ppm`/`.png`/`.kml` | si **no** está `--no-map` | | `.txt` + `.csv` | si está `--sft ` | | `splat.gp` + `*.gp` | si está `-h/-H/-p/-e/-l ` | --- ## 2. Construcción ```bash 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: ```bash 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 ` — 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-/`, `p-/`, etc.) para que no colisionen > al pedir varios plots a la vez: > > ```bash > 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 `` (texto) y `.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) ```bash 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 ```bash 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) ```bash 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) - `-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) ```bash 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 (5–40 km en pasos de 5, luego 50/60/70/80/90): ```bash splat-rs -t tx.qth -d sdf/ --olditm --no-map --sft atenuaciones.txt ``` **Extendida hasta 150 km**: ```bash 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): ```bash 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`: ```bash 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 `.az` y `.el`, splat-rs los detecta automáticamente y aplica el patrón en la pérdida y la tabla SFT: ```bash 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 ```bash 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 ```bash cat > obstaculos.udt <-to-.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 (`-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 - **``**: tabla de texto formateada con encabezado descriptivo - **`.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 `.az` y `.el` donde `` 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: ```bash sudo apt install gnuplot ``` ### Ejecución más lenta de lo esperado Verifica que rayon esté usando todos los cores: ```bash 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 (2002–2014) - **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).