Pipeline ETL para análise estatística do vento e otimização da orientação de pistas de aeródromos, conforme requisitos da RBAC 154 (ANAC/Brasil).
Dado um histórico de observações horárias do INMET, o HORO calcula:
- Fator de Operação (FO) — percentual do tempo em que o vento cruzado está abaixo do limite operacional (20 kt).
- Orientação ótima de pista — qual ângulo (0–179°) maximiza o FO.
- Declinação magnética — corrigida via NOAA para cada estação.
- Rosa dos ventos — visualização por janela temporal (5 / 10 / 15 / 20 anos).
- Vídeo e GIF animados — varredura de todos os ângulos de orientação de pista.
data/raw/ ← CSVs do INMET (entrada manual)
│
▼ Stage 1 — Ingest
data/bronze/ ← Parquet + JSON sidecar (dados brutos normalizados)
│
▼ Stage 2 — Validate (quality gate)
▼ Stage 3 — Transform
data/silver/ ← Parquet colunas [DATA, direction_deg, speed_kts]
│
▼ Stage 4 — Analyze (tabelas de vento por janela temporal)
▼ Stage 5 — Enrich (declinação magnética via NOAA)
▼ Stage 6 — Optimize (varredura 0–179° e melhor FO + frames)
data/gold/ ← JSON de resultados + frames JPG
│
▼ Stage 7 — Export
data/gold/exports/ ← Vídeo MP4 + GIF animado + FinalResult.json
O INMET disponibiliza dados históricos horários de todas as estações automáticas do Brasil.
- Acesse o mapa de estações: https://mapas.inmet.gov.br/
- Localize o aeródromo ou cidade mais próxima
- Clique na estação para ver o código (ex:
A511= Brasília,A601= São Paulo/Congonhas)
- Acesse a tabela de dados: https://tempo.inmet.gov.br/TabelaEstacoes/{CODIGO}
- Exemplo:
https://tempo.inmet.gov.br/TabelaEstacoes/A511
- Exemplo:
- Selecione o intervalo de datas (recomendado: últimos 5–20 anos)
- Clique em "Exportar CSV" — o site usa CAPTCHA, portanto o download é manual
- O arquivo será salvo como
generatedBy_react-csv.csv
# Recomendado: renomeie para o código da estação
mv generatedBy_react-csv.csv data/raw/A511.csv
# Alternativa: mantenha o nome original (funciona, mas lat/lon ficará como 0,0)
cp generatedBy_react-csv.csv data/raw/Nota: O novo portal do INMET não inclui metadados de localização no CSV. As coordenadas são usadas apenas para a consulta NOAA de declinação magnética (Stage 5). Para cálculo de FO e orientação de pista, as coordenadas não são necessárias.
# Clone o repositório
git clone <repo-url>
cd HOROv1
# Instale as dependências
pip install -r requirements.txt| Pacote | Uso |
|---|---|
pandas |
Processamento de séries temporais |
numpy |
Cálculos vetoriais |
windrose |
Geração da rosa dos ventos |
matplotlib |
Renderização de gráficos |
opencv-python |
Composição de frames e vídeo |
moviepy |
Geração de GIF animado |
selenium + webdriver-manager |
Consulta à NOAA (declinação magnética) |
chardet |
Detecção automática de encoding |
pyarrow / fastparquet |
Armazenamento em Parquet |
Unidecode |
Normalização de acentos |
python orchestrator.py --allpython orchestrator.py --all --station A511python orchestrator.py --all --dry-runAbra run_pipeline.ipynb para execução interativa com saídas inline.
O Stage 1 detecta automaticamente o formato do arquivo:
| Campo | Formato antigo BDMEP | Novo portal INMET (2024+) |
|---|---|---|
| Separador | ; |
; |
| Decimal | , |
, |
| Cabeçalho de metadados | ESTACAO:, LATITUDE:, LONGITUDE: |
Ausente |
| Coluna de velocidade | VENTO. VELO. (M/S) |
Vel. Vento (m/s) |
| Coluna de direção | VENTO. DIRE. (GR) |
Dir. Vento (m/s) |
| Encoding | Latin-1 / UTF-8 | UTF-8-SIG |
Atenção: A coluna
Dir. Vento (m/s)do novo portal tem rótulo incorreto no cabeçalho (deveria ser°). Os valores são graus (0–360). O pipeline interpreta corretamente.
data/gold/
├── {station}_results.json ← Resultado por janela temporal
├── exports/
│ ├── {station}/
│ │ ├── frames/ ← 180 frames JPG (um por ângulo de orientação)
│ │ ├── RunwayOrientation-5.mp4
│ │ ├── RunwayOrientation-5.gif
│ │ └── ... (10, 15, 20 anos)
│ └── FinalResult.json ← Consolidado de todas as estações
{
"A511": {
"metadata": { "latitude": -15.789, "longitude": -47.925, "altitude": "1160.96" },
"5y": { "runway": "36-18", "fo_pct": 98.7, "crosswind_pct": 1.3, "calm_pct": 4.2, "heading_deg": 5.0, "declination": -22.5 },
"10y": { "runway": "36-18", "fo_pct": 97.8, ... },
"15y": { ... },
"20y": { ... }
}
}HOROv1/
├── pipeline/
│ ├── core/
│ │ ├── config.py ← Configuração centralizada
│ │ ├── logger.py ← Logger estruturado
│ │ ├── exceptions.py ← Hierarquia de erros HOROError
│ │ └── models.py ← Dataclasses: BronzeRecord, SilverRecord, etc.
│ ├── utils/
│ │ ├── encoding.py ← Detecção de encoding (chardet + 7 fallbacks)
│ │ ├── geo.py ← Conversões DMS / decimal
│ │ └── video.py ← Geração de MP4 e GIF
│ ├── services/
│ │ ├── browser.py ← Chrome headless via webdriver-manager
│ │ ├── drawing.py ← Primitivos OpenCV
│ │ ├── wind.py ← Rosa dos ventos e cálculo de setores
│ │ └── runway.py ← Fator de Operação e otimização de orientação
│ └── stages/
│ ├── s01_ingest.py ← Raw CSV → Bronze Parquet
│ ├── s02_validate.py ← Quality gate
│ ├── s03_transform.py ← Bronze → Silver (m/s → kt, normalização)
│ ├── s04_analyze.py ← Silver → Wind Tables (5/10/15/20 anos)
│ ├── s05_enrich.py ← Declinação magnética via NOAA
│ ├── s06_optimize.py ← Varredura 0–179° → best FO + frames
│ └── s07_export.py ← Vídeo, GIF, FinalResult.json
├── data/
│ ├── raw/ ← Coloque os CSVs do INMET aqui
│ ├── bronze/ ← Gerado automaticamente
│ ├── silver/ ← Gerado automaticamente
│ └── gold/ ← Resultados finais
├── tests/ ← Testes unitários (pytest)
├── Standards/ ← RBAC154EMD07.pdf
├── orchestrator.py ← Ponto de entrada CLI
├── run_pipeline.ipynb ← Notebook interativo
└── requirements.txt
O pipeline aceita qualquer quantidade de dados, mas para análise estatisticamente válida conforme RBAC 154 recomenda-se mínimo de 5 anos de observações horárias completas (≈ 43.800 registros). Com menos dados, o FO será calculado sobre uma amostra não representativa — os resultados serão exibidos com um aviso.
O Stage 5 consulta o calculador da NOAA via Selenium (Chrome headless, gerenciado automaticamente). Quando as coordenadas são desconhecidas (lat=0, lon=0), o estágio pula a consulta e usa declinação = 0° com um aviso no log.
A varredura percorre 180 ângulos por janela temporal (720 total). Com dados completos de 5 anos (~43.800 linhas), leva ~6 min. Com o arquivo de exemplo de 7 dias (~161 linhas), leva ~4 min (gargalo: renderização dos 720 frames matplotlib).
- RBAC 154 EMD 07 — ANAC
- INMET — Mapa de Estações
- INMET — Portal de Tabelas
- NOAA — Calculadora de Declinação Magnética
John Heberty de Freitas — john.7heberty@gmail.com