Problem. Seyir irtifasındaki açık hava türbülansı (CAT) radarda görünmez; pilot raporu (PIREP) gönüllü, gecikmeli ve konumu kabadır; operasyonel ürünler (GTG, WAFS) NWP alanı üretir ve yerinde EDR ile doğrulanır.
Araştırma sorusu. Yalnız açık veriyle (OpenSky ADS-B, ERA5, AWC SIGMET, IEM PIREP) gerçek bir uçuş izinde seyir türbülansı riski hangi ölçülmüş beceriyle gösterilebilir ve bu sınır rota kararına nasıl taşınmalıdır?
Kısa cevap (nihai paket 2026-10-18). Becerisi sınırlı: Ellrod TI1, 163 günde 15.940 seyir PIREP'inde ROC-AUC 0,673 [0,661–0,684]; altın test günlerinde risk eşiğinde (7e-7) yakalama 0,50, yanlış alarm 0,25. Birleşik gösterge TI1'i az ama anlamlı geçiyor (+0,013 [+0,007; +0,020]). ML modeli altın günlerde TI1'i geçiyor (protokol modeli Random Forest +0,033 [+0,018; +0,049]; canlıdaki 9 Ekim Random Forest da +0,033), ama ROC-AUC 0,71'de kalıyor. Bu yüzden güvenlik SIGMET'e (sert kısıt) dayanır, TI1 A* rotasında yalnız yumuşak kısıttır.
Demo. Kimlik bilgisiz, çalışırken ağsız: Beş dakikada çalıştır. Kapsam yalnız CAT ve seyir safhası, doğrulama ABD verisiyle; çıktılar sertifikalı EDR değildir, sistem karar destek aracıdır.
Çekirdek ve ekler. Tezin çekirdeği dört katkıdır (Katkılar):
K1 barometrik irtifayla iz–ERA5 eşleştirmesi (fizik/eslestirme.py), K2 seyir
irtifası PIREP etiket hattı ve FL feet hatasının tespiti, K6 TI1 sınırının bağımsız
etiketle ölçülüp ürüne yansıtılması (fizik/turbulans_indeksleri.py,
ml/degerlendirme.py), K7 SIGMET sert / TI1 yumuşak kısıtlı A* rota
(rota/rota_optimizasyonu.py). Sanal PIREP, contrail, IWXXM, n8n, MCP, 3B
simülasyon ve CLI araçlarının çoğu mühendislik ekidir; tezin iddiasını taşımaz.
Ne yapar. Gerçek bir uçuşun (OpenSky/Trino) izini ERA5 küpüyle barometrik irtifada eşleştirir, Ellrod TI1 ve bulk Richardson göstergelerini hesaplar, sonuçları PostgreSQL'e yazar; FastAPI, harita önyüzleri ve MCP sunucusu üzerinden sunar.
Önemli sınırlama: TI1 ve 0–1 gösterge ölçeği (API alanı edr_proxy: birleşik
gösterge ölçeği, o yoksa TI1 görsel ölçeği) bir EDR (Eddy Dissipation Rate) değeri
DEĞİLDİR -- ~25-30 km çözünürlüklü reanaliz verisinden hesaplanan bir
araştırma/görselleştirme göstergesidir. TI1 görsel ölçeğinin katsayısı EDR ölçümüne
değil IEM PIREP sınıf koduna uydurulmuştur (bkz.
Sınırlamalar, kalibrasyon.py); bölgeden
bağımsız, kaba bir ölçektir, sertifikalı bir EDR sensörünün yerini TUTMAZ.
Doğruluk sayılarının tek kaynağı docs/sonuclar/ paketidir.
Sistemin kullanım sınıfı, veri kaynakları, hata durumlarındaki davranışı ve bilinen sınırları için bkz. Sistem Kartı. Mimari diyagramlar ve tasarım kararları: docs/mimari.md, docs/adr/.
Kimlik bilgisi (OpenSky, Copernicus) gerektirmez; ilk derleme internet ister (PyPI, npm, GitHub); çalışma anında dış veri kaynağı yok. Ağ yoksa Esri karoları gelmez; 3B harita yerel ülke sınırlarıyla çalışır. Depoyla gelen gerçek veri paketi (demo/): THY322'nin 15 Ocak 2019 rotası ve onu kapsayan ERA5 dilimi (toplam ~300 KB).
Docker ile (önerilen):
git clone <depo-adresi> && cd <depo>
cp .env.demo .env
docker compose --profile demo up -d --buildÖlçülen süre (derleme + demo analizi): temiz CI makinesinde 80 sn (GitHub
çalıştırıcısı, 14 Ekim 2026; her CI'da iş özetine yazılır); geliştirici
dizüstünde önbelleksiz derleme ~6,5 dk. Yığın
ayağa kalkınca demo servisi uçuşu analiz edip veritabanına yazar
(docker compose logs demo özeti gösterir). Sonra tarayıcıda:
- 3B harita: http://localhost:8000/harita/harita3d.html -- API anahtarı
demo-yerel-yonetici, listeden THY322'yi seç. - Rota simülasyonu: http://localhost:8000/harita/ucus_simulasyonu.html (örn. 41.0, 29.0 → 40.5, 43.5; FL350; 2019-01-15 20:00).
- API belgesi: http://localhost:8000/docs
Docker olmadan (yalnızca analiz ve harita):
pip install -e .
turbulans-demo # ciktilar/turbulans_haritasi_THY322_2019-01-15.htmlPostgreSQL yoksa sonuç kaydedilmez ama özet ve harita yine üretilir. Jüri sunumu için demo akışı, sunum planı ve poster: docs/sunum/. Demo anahtarları herkesçe bilinir; bu yığını ağa açmayın. Gerçek kurulum için aşağıdaki Kurulum bölümüne bakın.
┌─────────────────┐
OpenSky/Trino ────────►│ veri_yukleme.py │
(callsign→icao24→rota) └────────┬─────────┘
│
Copernicus/ERA5 (.nc) ──────────┤
▼
┌───────────────┐ ┌────────────────────┐
│ eslestirme.py │─────►│ turbulans_indeksleri│
│ (TI1+Richard.)│ │ (Ellrod TI1, Ri) │
└───────┬───────┘ └────────────────────┘
│
┌─────────────┼─────────────┐
▼ ▼ ▼
veritabani.py harita.py ucus_analizi /
(PostgreSQL, (Folium HTML) toplu_analiz.py /
models.py) web_arayuzu.py (CLI/UI)
│
┌─────────────┼─────────────────┐
▼ ▼ ▼
api_servisi.py mcp_postgres_ (Alembic ile
(FastAPI REST sunucusu.py şema yönetimi)
+ WebSocket) (Claude Code
için salt okunur)
Aynı mimarinin görsel (GitHub'da otomatik render olan Mermaid) hali -- ML sınıflandırıcı ve SIGMET doğrulama akışları dahil:
flowchart TB
OS["OpenSky/Trino<br/>state vectors"] --> VY["veri_yukleme.py"]
ERA5["Copernicus/ERA5<br/>.nc veri küpü"] --> VY
VY --> ES["eslestirme.py<br/>(vektörel eşleştirme)"]
ES --> TI["turbulans_indeksleri.py<br/>(Ellrod TI1 + Richardson)"]
PIREP["IEM PIREP arşivi<br/>(gerçek pilot raporları)"] --> MLV["ml_veri_hatti.py<br/>(gece işi)"] --> MLE["ml_otomatik_egitim.py"] --> MODEL[("turbulans_ml_modeli.joblib")]
TI -.->|"özellik çıkarımı"| MODEL
TI --> DB[("PostgreSQL<br/>ucuslar / edr_olcumleri")]
DB --> API["api_servisi.py<br/>(FastAPI REST + WebSocket)"]
MODEL --> API
SIGMET["AWC SIGMET arşivi<br/>(sadece ABD hava sahası)"] --> SD["sigmet_dogrulama.py"] --> API
ERA5 -.->|"A* rota optimizasyonu"| RO["rota_optimizasyonu.py"] --> API
API --> H3D["web/harita3d.html<br/>(3D canlı harita)"]
API --> SIM["web/ucus_simulasyonu.html<br/>(rota karşılaştırma)"]
API --> ST["web_arayuzu.py<br/>(Streamlit)"]
DB --> MCP["mcp_postgres_sunucusu.py<br/>(Claude Code, salt okunur)"]
Paket yapısı (src/turbulans_radar/, src layout -- pip install -e . ile
kurulur, komut satırı araçları [project.scripts] ile gelir):
turbulans_radar/
config.py, ayar_dogrulama.py, loglama.py, hata_yardimcisi.py, -> çekirdek: ayarlar (*_FILE sırları), doğrulama ve ağa açılışta
konsol_kurulumu.py, uretim_bilgisi.py, yeniden_deneme.py, kapalı başlama, log, hata mesajları, sürüm bilgisi, yeniden deneme,
webhook.py, ucus_kurallari.py webhook, uçuş kuralları
depo/ models.py, veritabani.py -> SQLAlchemy ORM + senkron/asenkron PostgreSQL erişimi
gorev_deposu.py, dagitik_kilit.py -> kalıcı görev kuyruğu, advisory lock
kup_katalogu.py, kaynak_durumu.py, veri_butcesi.py -> küp kataloğu, veri kaynağı durumu, günlük indirme bütçesi
denetim.py, hiz_siniri.py, geri_bildirim_deposu.py, sanal_pirep_deposu.py
veri/ veri_yukleme.py, opensky_onbellegi.py -> NetCDF yükleme/önbellek, OpenSky/Trino + Parquet rota önbelleği
veri_saglayicilari.py, era5_saglayici.py, veri_indirme.py -> canlı GFS, uçuşa özel ERA5 (CDS, ARCO yedek)
sigmet_saglayici.py, iwxxm.py -> AWC SIGMET'leri (Ankara FIR dahil), IWXXM dışa aktarımı
kisitli_saha_saglayici.py, openaip_saglayici.py, saha_aktivasyonu.py, fir_sinirlari.py
madis_edr.py, canli_adsb.py, kimlik_dogrulama.py
fizik/ turbulans_indeksleri.py, eslestirme.py -> Ellrod TI1, Richardson, rota <-> küp eşleştirme
edr_esleme.py, ti1_esigi.py, kalibrasyon.py -> birleşik gösterge, kaynağa göre eşik, görsel ölçek
birim_donusumleri.py, cografya.py, iz_bulutu.py, sanal_pirep.py
rota/ rota_optimizasyonu.py, risk_katmanlari.py -> A* (yanal + irtifa), SIGMET/kısıtlı saha sert, TI1 yumuşak kısıt
a_yildiz.py, geometri.py, ruzgar.py -> yanal ızgara/ATS A*, büyük daire, rüzgâr üçgeni
brifing.py, bulgular.py, czml.py -> riskli bölüm/kabin/brifing, dispeç bulguları, CesiumJS çıktısı
hava_yolu_agi.py, ucus_seviyeleri.py, fpl.py -> ATS/FRA ağı, yarım daire kuralı, FPL Madde 15
performans_modeli.py, dikey_kesit.py, kalkis_penceresi.py -> OpenAP yakıt, kesit, kalkış penceresi
dogrulama/ rota_backtest.py, bagimsiz_kanit.py, sigmet_dogrulama.py -> backtest ve SIGMET/PIREP bağımsız kanıt
sanal_pirep_dogrulama.py, anomali_tabani.py, ayirma_gostergesi.py
ml/ turbulans_ml_modeli.py, ml_veri_hatti.py, ml_otomatik_egitim.py, ml_egitimi.py -> model, gece işi, kapı
degerlendirme.py, sonuc_disa_aktarimi.py, sonuc_paketi.py -> TI1 referansı, nihai sonuç paketi
belirsizlik.py, kayma_izleme.py, model_butunlugu.py, ozellik_deposu.py, madis_hatti.py
edr_eslestirme.py, edr_kalibrasyonu.py, gosterge_degerlendirme.py, duyarlilik_analizi.py,
rf_deneyi.py, tip_analizi.py -> deneyler (altın günler dışında)
yeni_gun_degerlendirmesi.py -> dondurma sonrası yeni günlerde tek değerlendirme (protokol §10)
analiz/ ucus_analizi.py, toplu_analiz.py -> uçtan uca uçuş analizi
esik_esleme.py, gfs_toplulugu.py, kacinma_baslangici.py, ayriklastirma.py,
dedektor_duyarliligi.py, sanal_pirep_hatti.py -> ek analizler
api/ api_servisi.py, semalar.py, guvenlik.py, ortak.py -> FastAPI REST + WebSocket, şemalar, anahtar/rol, CSP
metrikler.py, rota_onbellegi.py
yollar/ analiz.py, ucuslar.py, ml.py, hava_sahasi.py, geri_bildirim.py
isci/ gorev_iscisi.py -> uzun işler (analiz, backtest, ML gece işi) ayrı süreçte
arayuz/ harita.py, web_arayuzu.py -> Folium zaman kaydırıcılı harita, Streamlit arayüzü
cli/ demo.py, demo_ekranlari.py, performans_olcumu.py, statik_indir.py, openapi_disa_aktar.py,
mcp_postgres_sunucusu.py, aip_ats_agi.py, aip_enr51.py, airac_yenile.py, ornek_ucus_bul.py, veri_kontrol.py,
kimlik_kontrol.py
web/ -> harita3d.html/.js (MapLibre) + ucus_simulasyonu.html/.js (CesiumJS); vendor/
otomasyon/ -> yedek + geri yükleme tatbikatı, Caddyfile (TLS vekili), uygulama rolü
migrations/, alembic.ini -> Alembic şema migration'ları
tests/ -> pytest (birim + PostgreSQL + gerçek veri + Playwright)
git clone <bu-repo>
cd files
pip install -e ".[dev]" # paket + sabitlenmiş bağımlılıklar + komut satırı araçları + test/lint araçları
cp .env.example .env # OpenSky + PostgreSQL + API_ANAHTARI bilgilerini gir
alembic upgrade head # veritabanı şemasını kur/güncelleSadece çalıştırmak (geliştirme araçları olmadan) için pip install -e . yeterlidir.
Web arayüzlerinin kütüphanelerini (CesiumJS, MapLibre) yerelden sunmak için
bir kez turbulans-statik çalıştır (yaklaşık 30 MB, web/vendor/'a; git'e
girmez). Çalıştırılmazsa sayfalar aynı sürümü CDN'den yükler. Aynı komut,
koordinatsız SIGMET'ler için FIR sınır verisini de veri_dosyalari/'na
indirir (bkz. "Koordinatsız SIGMET'ler" bölümü); çalıştırılmazsa bu SIGMET'ler
eski (eleme) davranışıyla işlenir. Docker imajı ikisini de derlenirken
kendisi yapar.
.env'e girilmesi gerekenler (bkz. .env.example): OPENSKY_USERNAME/
OPENSKY_PASSWORD (OpenSky hesabı, tarihsel veri erişimi onaylanmış
olmalı -- https://opensky-network.org/my-opensky/request-data),
POSTGRES_* (host/port/kullanıcı/şifre/veritabanı), API_ANAHTARI
(python -c "import secrets; print(secrets.token_urlsafe(32))" ile üret).
Hava durumu veri küpünü (ocak_2019_turbulans.nc, Copernicus/ERA5'ten
manuel indirilmiş) proje köküne koyman gerekir -- büyük olduğu için
.gitignore'da, repoya dahil değildir.
docker compose up --buildBu, PostgreSQL'i, API'yi (önce tek seferlik migrate_yedegi doğrulanmış bir yedek alır,
migrate alembic upgrade head çalıştırır; ikisi başarıyla bitmeden API başlamaz) ve uzun
işleri çalıştıran ayrı worker servisini tek komutla ayağa kaldırır
(ölçeklemek için: docker compose up --scale worker=3). .env dosyanın hazır olması gerekir;
POSTGRES_HOST konteynerler arası iletişim için otomatik olarak compose
servis adına (db) çevrilir. API http://localhost:8000'de, Swagger
http://localhost:8000/docs'ta olur. Konteyner otonom çalışır: canlı
AWC SIGMET'lerini 15 dakikada bir kendisi yeniler
(SIGMET_OTOMATIK_GUNCELLEME_DAKIKA), anlık rotalar için canlı GFS verisini
indirir (canli_veri/ volume'unda saklanır). PostgreSQL ve API portları
yalnızca 127.0.0.1'e açıktır; ağdaki bir cihaz API'ye erişecekse .env'de
API_YAYIN_ADRESI=0.0.0.0 (anahtarlar düz HTTP'den geçer, yalnızca güvenilen
ağda). Uygulama süreçleri root olmayan turbulans (uid 1000) kullanıcısıyla
çalışır: giriş betiği (otomasyon/konteyner_giris.sh) yazılabilir bağlı
klasörleri ve model volume'unu bu kullanıcıya sahiplendirip yetkiyi düşürür
(Linux'ta Docker eksik klasörleri root olarak oluşturur). docker compose exec
ile açılan komutlar giriş betiğinden geçmez ve root çalışır; dosya yazan bir
komutu docker compose exec --user turbulans ... ile çalıştırın.
İşçi durdurulunca (docker compose stop/up dahil) çalışan görevi
GOREV_DURDURMA_BEKLEME_SANIYE (240) bekler; ML gece işi süren CDS isteğini
bitirip yarida_kaldi olarak durur ve zamanlayıcı aynı gün yeniden dener.
Bu yüzden işçinin durması 5 dakikaya kadar sürebilir (stop_grace_period).
- ERA5 arşiv küpleri imaja dahil değildir (boyut);
ocak_2019_turbulans.nc,era5_egitim_verisi/vepirep_ham/API ve işçiye/verialtında salt okunur bağlanır. Proje kökünün tamamı bağlanmaz:.env, yedekler ve.gitkonteynerden okunamaz. Başka bir klasör için.env'deYEREL_VERI_KOKU,HAVA_DURUMU_DOSYA_ADI,EK_HAVA_DURUMU_KLASOR_ADI,ML_PIREP_ARSIV_KLASOR_ADI. Dosya yoksa Docker yerine boş bir klasör açar ve o küp atlanır. - Kod salt okunur: imajdaki kod root'a ait ve 755 izinlidir; uygulama kullanıcısı (uid 1000) yalnızca bağlanan veri klasörlerine yazabilir.
- Uçuşa özel ERA5 dilimleri, ARCO saatlik önbelleği ve OpenSky rota
önbelleği proje klasöründeki
era5_ucus_verisi/,era5_arco_onbellek/veopensky_onbellek/klasörlerine bağlanır (bind mount): konteyner silinse de kalır, yerel CLI ile aynı önbelleği paylaşır ve katalogdaki göreli yollar iki tarafta da geçerlidir. Konteynerde OpenSky tarayıcı girişi yapılamadığı için önbellekteki rotalar Trino'suz analiz edilir. - Copernicus CDS kimliği:
.env'deCDSAPI_RC_DOSYASI(compose'u çalıştıran makinedeki.cdsapircyolu, WSL'de örn./mnt/c/Users/<kullanici>/.cdsapirc) verilirse dosya API ve işçiye secret olarak/run/secrets/cdsapirc(salt okunur) bağlanır veCDSAPI_RCoraya ayarlanır; imaja ya da ortam değişkenlerine girmez. Verilmezse boş bir dosya bağlanır, yığın yine açılır; CDS başarısız olur ve ARCO yedeği (ARCO_ONBELLEK_MAKS_GB, varsayılan 20 GB) kullanılır. - ML modeli ve sürümleri proje kökündeki
model_deposu/klasöründe tutulur (konteynerde/app/model_deposu'na bağlanır; yereldeMODEL_KLASORUvarsayılanı damodel_deposu): Docker'daki API/işçi ile yerelde çalışan Streamlit veturbulans-mlAYNI aktif modeli ve sürüm listesini görür./aktiflestirile yapılan geri dönüş ve konteyner içinde yapılan eğitim konteyner yeniden oluşturulunca kaybolmaz; yedek servisi klasörü salt okunur kopyalar. (6 Ekim 2026'ya kadar kullanılanturbulans_modellervolume'u silinmedi; içeriği bu klasöre kopyalandı.)
turbulans-ornek-ucus # gerçek, o gün kayıtlı bir callsign bul
turbulans-analiz THY1234 2019-01-01 # analiz et -- PostgreSQL'e yazar + harita üretirHer script --help ile kullanım bilgisi verir. Sonuç ucuslar/
edr_olcumleri tablolarına yazılır (aynı uçuş/tarih tekrar analiz
edilirse eski kayıt silinip yenisiyle değiştirilir); harita
ciktilar/turbulans_haritasi_<uçuş>_<tarih>.html'e kaydedilir.
streamlit run src/turbulans_radar/arayuz/web_arayuzu.pyUçuş numarası ve tarihi bir kutuya yazıp "Analiz Et"e basman yeterli;
sonuç tablosu ve harita direkt sayfada görünür. Arkada aynı turbulans-analiz
mantığı çalışır -- bu sadece görsel bir ön yüz. Varsayılan uçuş, depoda önbelleği
olan THY322 / 2019-01-15'tir (OpenSky girişi gerektirmez). Sayfa yalnızca
127.0.0.1'de dinler (.streamlit/config.toml).
turbulans-toplu-analiz ucuslar.csv # en az ucus_numarasi, tarih sütunlarıHer uçuş kendi kaydını PostgreSQL'e yazar ve kendi haritasını üretir; ayrıca
hepsinin özetini ciktilar/toplu_analiz_ozeti.csv'de toplar. Bir uçuşta
hata olursa diğerlerinin analizi durmaz; OpenSky'yi yormamak için uçuşlar
arasına kısa bir bekleme konur.
POST /api/v1/analiz/toplu ile n8n'in tetiklediği (onlarca/yüzlerce uçuşluk
olabilen) toplu işlerde harita üretimi otomatik olarak kapatılır
(harita_uret=False, bkz. isci/gorev_iscisi.py) -- sunucuda kimsenin
açmayacağı bir HTML dosyasıyla ciktilar/'ı sınırsız büyütmek yerine sonuç
zaten PostgreSQL'e yazılır ve GET /ucuslar/{ucus}/{tarih} (+ csv/geojson)
ile okunur. CLI'dan (turbulans-toplu-analiz) çalıştırıldığında harita
üretimi varsayılan olarak açık kalır.
turbulans-veri-kontrol N10VZ 2019-01-15 # önce turbulans-analiz ile analiz etmiş olman gerekirVeri küpünün çözünürlüğünü (grid/zaman adımı) ve PostgreSQL'deki TI1 değerlerinin ne kadar çeşitli olduğunu (çok az benzersiz değer varsa veri küpü muhtemelen çok kaba) kontrol eder.
uvicorn turbulans_radar.api.api_servisi:app --reload --port 8000
# Swagger/OpenAPI: http://localhost:8000/docsSwagger (/docs), uç noktaları Uçuşlar/Analiz/Simülasyon/Türbülans Tahmini/Eşikler/Sistem etiketleriyle gruplar.
Sunucuyu ayağa kaldırmadan API'yi keşfetmek için: openapi.json (ham OpenAPI
şeması, /openapi.json ile AYNI) ve turbulans_radar.postman_collection.json
(tüm uç noktaları X-API-Key başlığıyla hazır içeren bir Postman
koleksiyonu -- taban_url/api_anahtari koleksiyon değişkenlerini
doldurman yeterli) repoya dahil. Endpoint eklendikçe/değiştikçe
turbulans-openapi ile yeniden üretilebilir -- canlı /openapi.json
her zaman en güncel/otoriter kaynaktır, bu iki dosya sadece bir anlık
görüntü (snapshot) kolaylığı sağlar.
| Metod | Yol | Açıklama |
|---|---|---|
| GET | /saglik |
Sağlık kontrolü (anahtarsız). ?derin=true ile PostgreSQL'e gerçekten bağlanmayı dener (deploy sonrası kontrol için) |
| GET | /api/v1/ucuslar |
Kaydedilmiş uçuşları listeler; {toplam_sayi, ucuslar} döner (limit, 1-500; ucus_numarasi_arama kısmi eşleşme, baslangic_tarih/bitis_tarih ile filtrelenebilir) |
| GET | /api/v1/ucuslar/{ucus_numarasi}/{tarih} |
Bir uçuşun ölçüm noktaları (olcum_limit/olcum_offset ile sayfalı) |
| DELETE | /api/v1/ucuslar/{ucus_numarasi}/{tarih} |
Kayıtlı bir uçuşu (ölçümleriyle birlikte) siler -- bulunamazsa 404, silinirse 204 |
| DELETE | /api/v1/ucuslar |
Filtreye (ucus_numarasi_arama/baslangic_tarih/bitis_tarih) uyan TÜM uçuşları toplu siler -- filtresiz istek 400 ile reddedilir (yanlışlıkla tüm tabloyu boşaltmayı önlemek için) |
| GET | /api/v1/ucuslar/{ucus_numarasi}/{tarih}/csv |
Bir uçuşun TÜM ölçümlerini (sayfalama olmadan) CSV olarak indirir |
| GET | /api/v1/ucuslar/{ucus_numarasi}/{tarih}/geojson |
Bir uçuşun TÜM ölçümlerini bir GeoJSON FeatureCollection'ı olarak indirir (QGIS/geopandas vb. için) |
| POST | /api/v1/analiz/ucus |
Tek bir uçuşu arka planda analiz eder, gorev_id döner |
| POST | /api/v1/analiz/toplu |
Birden fazla uçuşu arka planda analiz eder |
| POST | /api/v1/analiz/rota |
OpenSky'a bağlanmadan, dışarıdan yüklenen bir ADS-B izini (noktalar: zaman, enlem, boylam, irtifa_m) analiz edip kaydeder -- tarayıcı girişi gerektirmediği için sunucu/Docker'da da çalışır |
| GET | /api/v1/analiz/durum/{gorev_id} |
Tetiklenen bir analizin durumunu sorgular |
| GET | /api/v1/esikler |
TI1 renklendirme eşiklerini döner (web/harita3d.html bunları kullanır) |
| GET | /api/v1/ucuslar/{ucus_numarasi}/{tarih}/sigmet-dogrulama |
TI1'i gerçek AWC SIGMET'leriyle karşılaştırır |
| GET | /api/v1/simulasyon/ucak-profilleri |
3D uçuş simülasyonu için uçak modeli seçim listesi |
| POST | /api/v1/simulasyon/rota |
Büyük daire vs rüzgar-optimize rota + CZML döner; aktif SIGMET'ler sert kısıt olarak uygulanır (bkz. aşağıdaki bölüm) |
| POST | /api/v1/sigmet/guncelle |
AWC'den canlı SIGMET'leri çekip veritabanını günceller (n8n/cron periyodik tetikler) |
| GET | /api/v1/sigmet |
Şu an geçerli SIGMET'ler (kutu/tehlike filtresiyle) -- önyüzlerin yasak bölgeleri çizmesi için |
| GET | /api/v1/kisitli-sahalar |
Şu an geçerli kısıtlı/yasak hava sahaları (kutu filtresiyle) |
| POST | /api/v1/kisitli-sahalar?kaynak=... |
GeoJSON FeatureCollection içe aktarır (örn. n8n: NOTAM -> geçici kısıt); eskileri_kaldir=true kaynağı tamamen yeniler |
| DELETE | /api/v1/kisitli-sahalar/{dis_kimlik} |
Bir kısıtlı sahayı siler |
| POST | /api/v1/veri/canli/hazirla |
Bir bölge/zaman için canlı GFS küpünü arka planda hazırlar (katalogda tazesi varsa onu kullanır), 202 + gorev_id döner |
| GET | /api/v1/veri/kupler |
Hava durumu küpü kataloğu (kaynak, model çalıştırması, kapsam, seviyeler) |
| POST | /api/v1/backtest/ucuslar/{ucus_numarasi}/{tarih} |
Bir uçuşun gerçek izini büyük daire ve A* rotasıyla karşılaştırıp kaydeder |
| POST | /api/v1/backtest/toplu |
Backtest'i olmayan uçuşları arka planda karşılaştırır (ör. gecelik bir zamanlayıcıdan), gorev_id döner; ?yenile=true mevcut backtest'leri de en eskiden başlayarak yeniden hesaplar (algoritma değişince bayat sonuç kalmaz) |
| GET | /api/v1/backtest |
Tüm backtest sonuçları + filo geneli özet |
| POST | /api/v1/turbulans/tahmin |
Tek nokta için fizik (TI1) + gerçek PIREP verisiyle eğitilmiş ML tahminini karşılaştırmalı döner |
| GET | /api/v1/turbulans/model-bilgisi |
ML modelinin seçim gerekçesi/metrikleri (recall, F1, ROC-AUC vb.) + eğitim tarihini döner; model henüz eğitilmediyse dürüstçe egitildi_mi: false |
| GET | /api/v1/turbulans/model-versiyonlari |
Şimdiye kadar eğitilmiş TÜM model versiyonlarını (en yeni önce) listeler |
| POST | /api/v1/turbulans/model-versiyonlari/{versiyon_id}/aktiflestir |
Geçmiş bir model versiyonunu YENİDEN EĞİTİM GEREKMEDEN aktif model yapar (rollback); bilinmeyen versiyon_id 404 döner |
| POST | /api/v1/sanal-pirep/iz |
(yönetici) Havayolu ADS-B beslemesinden bir uçağın izi: seyirdeki irtifa sapmalarını sanal PIREP olarak kaydeder (bkz. "Sanal PIREP") |
| GET | /api/v1/sanal-pirep |
Koridordaki sanal PIREP olayları ve uzay-zaman kümeleri (son_saat, bitis, kutu, sadece_dogrulanmis) |
| WS | /ws/uyarilar?bilet=... |
TI1 "orta-şiddetli" eşiği aşılınca ve en az 2 uçağın doğruladığı sanal PIREP'te canlı uyarı yayınlar |
| GET | /saglik?derin=true |
(anahtarsız) Veritabanı + SIGMET tazeliği, canlı GFS, görev kuyruğu, kısıtlı sahalar, küp önbelleği, yerel kütüphaneler; operasyonel sorunda durum: bozulmus |
| GET | /api/v1/sistem/durum |
Aynı rapor + kaynak başına son hata metinleri (anahtarlı) |
| GET | /harita/harita3d.html |
3D/canlı harita önyüzü (statik, tarayıcıda açılır) |
| GET | /harita/ucus_simulasyonu.html |
3D uçuş simülasyonu önyüzü (statik, tarayıcıda açılır) |
Örnek:
curl -X POST http://localhost:8000/api/v1/analiz/ucus \
-H "X-API-Key: $API_ANAHTARI" -H "Content-Type: application/json" \
-d '{"ucus_numarasi": "THY1234", "tarih": "2019-01-01"}'
curl http://localhost:8000/api/v1/ucuslar/THY1234/2019-01-01 \
-H "X-API-Key: $API_ANAHTARI"- API anahtarı:
/api/v1/*altındaki tüm uç noktalarX-API-Keybaşlığı gerektirir (.env->API_ANAHTARI), sabit zamanlı (secrets.compare_digest) karşılaştırılır. Anahtar yanlış/eksikse 401, sunucuda hiç tanımlı değilse 503. - Roller:
API_ANAHTARIyöneticidir (n8n, operasyon). İsteğe bağlıAPI_PILOT_ANAHTARIEFB/pilot istemcisi içindir: okuma, rota simülasyonu, tahmin ve canlı uyarılar; uçuş silme, kısıtlı saha değişikliği, model aktifleştirme, görev tetikleme ve/sistem/durumiçin 403. Kokpitteki cihaza sadece pilot anahtarı konur. Web sayfaları anahtarı sadece oturum boyunca (sessionStorage) tutar. - Kişi/cihaz başına anahtar ve rotasyon:
API_ANAHTARLARIilekimlik:rol:anahtarbiçiminde (virgülle) ek anahtarlar tanımlanır, örn.ops-ayse:yonetici:...,efb-tc-jfa:pilot:.... Rotasyon: yeni anahtarı ekle, istemciler geçince eskisini çıkar. - Denetim kaydı:
/api/v1altındaki her değiştirici istek (POST/PUT/ PATCH/DELETE; kısıtlı saha silme, model aktifleştirme, toplu silme, rota hesabı...)denetim_kayitlaritablosuna yazılır: anahtar kimliği, rol, yöntem, yol, sonuç kodu, IP, süre. Reddedilen denemelerkimliksizolarak görünür; sorgu dizesindeki webhook URL'si maskelenir. Okuma:GET /api/v1/denetim(yönetici). Saklama:DENETIM_SAKLAMA_GUN(180). - Hız sınırı ve yük: Sayaç PostgreSQL'de, tüm API süreçlerince
paylaşılır; veritabanına ulaşılamazsa istek reddedilmez, süreç içi sayaca
düşülür. Rota/tahmin uçları istemci başına sınırlı ve süreç başına
eşzamanlılık tavanlı (
ROTA_HESABI_DAKIKADA_MAKS,TAHMIN_DAKIKADA_MAKS,AGIR_HESAP_MAKS_ESZAMANLI); anahtarsız/saglik?derin=trueSAGLIK_ONBELLEK_SANIYEönbelleklidir. - WebSocket bileti:
/ws/uyarilaranahtarı URL'de (erişim loglarında) taşımamak içinPOST /api/v1/ws-bileti'den alınan 60 sn'lik, sunucu anahtarıyla imzalı, tek kullanımlık bilet (?bilet=) kullanır;?api_key=kabul edilmez. - API belgeleri:
/docs,/redoc,/openapi.jsonyalnızca API bu makineye bağlıyken (API_YAYIN_ADRESIboş/127.0.0.1) açıktır; ağa açılınca kapanır.API_BELGELERI_ACIK=true|falseile zorlanabilir. - TLS: API düz HTTP konuşur.
API_YAYIN_ADRESI=0.0.0.0ile ağa açılırsa anahtarlar açık metin gider (açılışta uyarı loglanır); güvenilmeyen ağda önüne TLS sonlandıran bir ters vekil koyun. - TLS vekili (
--profile uretim):vekilservisi (Caddy 2.8.4,otomasyon/Caddyfile) 80/443'ü dinler, HTTPS'i sonlandırır, HSTS ekler ve API'ye iç ağdan (vekil_agi, sabit adres 172.31.250.200) gider. API'nin host portu 127.0.0.1'de kalır..env.uretim.example:AG_ACILISI=true(kapalı başlama kuralları ve/docskapanır),FORWARDED_ALLOW_IPS=172.31.250.200(IP başına hız sınırı ve denetim kaydı gerçek istemciyi görür),ALAN_ADI+VEKIL_TLS(e-posta: Let's Encrypt;internal: Caddy'nin yerel CA'sı, EFB'ye kök sertifika yüklenir:docker compose cp vekil:/data/caddy/pki/authorities/local/root.crt .). WebSocket (/ws/uyarilar) vekilden geçer. Başlatma:docker compose --profile uretim up -d. - Tarayıcı güvenlik başlıkları: Her yanıtta
X-Content-Type-Options: nosniff,Referrer-Policy: no-referrer,X-Frame-Options: DENY,Permissions-Policy./haritasayfalarında CSP: betikler yalnız bu sunucudan (script-src 'self'; satır içi betik,onerror=ve CDN yedeği yok, kütüphanelerweb/vendor'dan), altlık karolar Esri'den,frame-ancestors 'none'. CesiumJS kendi içindenew Functionve WebAssembly kullandığı için yalnız simülasyon sayfası ve Cesium dosyaları'unsafe-eval' 'wasm-unsafe-eval' blob:alır./docs(yalnız yerelde açık) CSP almaz. Tarayıcı testleri CSP ihlalini hata sayar. Anahtar hâlâsessionStorage'dadır; CSP satır içi betik enjeksiyonunu engelleyerek bunu korur. - Sırlar dosyadan (
*_FILE, Docker secret):API_ANAHTARI,API_PILOT_ANAHTARI,API_ANAHTARLARI,POSTGRES_PASSWORD,MCP_POSTGRES_PASSWORD,OPENSKY_PASSWORD,OPENSKY_CLIENT_SECRET,OPENAIP_API_ANAHTARIiçinAD_FILE=/run/secrets/...verilirse değer dosyadan okunur ve ortamdaki değeri ezer; dosya yoksa ya da boşsa süreç başlamaz. Üretimde.envyerinedocker-compose.override.ymlile (depoya girmez):services.api.secrets: [api_anahtari],services.api.environment.API_ANAHTARI_FILE: /run/secrets/api_anahtari,secrets.api_anahtari.file: /guvenli/yol/api_anahtari; işçi için aynısı.dbimajıPOSTGRES_PASSWORD_FILE'ı zaten destekler. - Ağa açılışta kapalı başlama:
API_YAYIN_ADRESIyerel değilse ya daAG_ACILISI=trueise API ve işçi şu durumlarda hiç başlamaz ve sorunların hepsini tek mesajda (değerleri yazmadan) listeler: 32 karakterden kısa ya dademoile başlayan herhangi bir API anahtarı; boş,postgresya da demo DB şifresi; uygulamanın süper kullanıcıyla bağlanması (UYGULAMA_POSTGRES_*tanımsız);KISITLI_SAHA_ORNEK_VERI_YUKLE=true;MODEL_BUTUNLUK_ZORUNLU=false. Yerel geliştirme (127.0.0.1) bu kurallardan etkilenmez. - Konteyner kabuğu: Uygulama süreçleri uid 1000 ile çalışır, ama
docker compose execvarsayılan olarak root açar; elle komut içindocker compose exec -u turbulans api ...kullanın. - Girdi doğrulama:
tarihgerçek bir tarih olarak,ucus_numarasiharf/rakam + en fazla 8 karakter olarak doğrulanır (422 döner). - Hata gizliliği: 500/503 yanıtları ham exception mesajını (SQL,
bağlantı dizesi vb.) istemciye döndürmez; tam ayrıntı sunucu tarafında
(stderr,
loglama.py) loglanır. - Hız sınırlama:
/api/v1/analiz/*, kendi API'sini kötüye kullanıma karşı bellek-içi bir pencere sayaçla korur (varsayılan: 60 saniyede en fazla 5 istek, aşılırsa 429) -- dışarıdan tetiklenen aşırı istekle OpenSky'yi dolaylı yormamak için.DELETE /api/v1/ucuslar*(tekli ve toplu silme) da AYNI desenle (kendi ayrı penceresiyle) korunur -- yanlışlıkla/kötüye kullanımla art arda çok sayıda silme isteğine karşı. - Asenkron: okuma uç noktaları
asyncpgtabanlı, event loop'u bloklamaz. Uzun işler API sürecinde çalışmaz (bkz. aşağıdaki görev kuyruğu). - CORS: varsayılan kapalı;
.env'dekiCORS_IZIN_VERILEN_KAYNAKLAR(virgülle ayrılmış origin listesi) ile açılır. - Görev kuyruğu ve işçiler: uzun işler (
/analiz/ucus,/analiz/rota,/analiz/toplu,/backtest/toplu,/veri/canli/hazirla) PostgreSQL'dekianaliz_gorevleritablosuna kuyruk olarak eklenir ve istek hemen202 {"gorev_id", "durum": "kuyrukta"}döner; ayrı bir mesaj kuyruğu altyapısı gerekmez (gorev_deposu.py). İşçiler (isci/gorev_iscisi.py) sıradaki göreviFOR UPDATE SKIP LOCKEDile alır -- birden çok işçi süreci aynı görevi iki kez almaz. EşzamanlılıkGOREV_ISCI_SAYISIile sınırlıdır (ağır bir toplu iş API'yi yavaşlatmaz). Çalışan görevin işçisi kalp atışı gönderir; işçi çökerse ya da yeniden başlarsa görevGOREV_BAYAT_SANIYEsonra yeniden kuyruğa girer (GOREV_MAKS_DENEME'ye kadar), sonrayarida_kaldiolur. Durumlar:kuyrukta -> calisiyor -> tamamlandi | basarisiz | hata | yarida_kaldi. Varsayılan olarak API kendi içinde gömülü bir işçi başlatır (GOREV_GOMULU_ISCI); ayrı süreç içinturbulans-isci(Docker'daworkerservisi), belirli işlere ayrılmış işçi içinGOREV_ISCI_TURLERI. Bitmiş görevler 7 gün sonra otomatik silinir. - Webhook bildirimi:
bildirim_webhook_urlverilirse, analiz bitince sonuç oraya POST edilir -- n8n'in Webhook node'u bunu dinleyip/api/v1/analiz/durum/{gorev_id}'yi periyodik yoklamaya gerek bırakmaz. SSRF koruması (webhook.py): varsayılan olarak sadece genel (public) adreslere gönderilir; hem istek anında (yazılan adres) hem gönderim anında (adın ÇÖZÜMLENDİĞİ IP) kontrol edilir, yönlendirme izlenmez. DNS rebinding'e karşı istek doğrulanan IP'ye sabitlenir (ikinci bir DNS sorgusu yapılmaz); Host başlığı ve TLS sertifika doğrulaması orijinal alan adıyla yapılır. Aynı makinedeki/iç ağdaki n8n için host'u.env'dekiWEBHOOK_IZIN_VERILEN_HOSTLAR'a ekle (örn.localhost,n8n); liste doluysa sadece listedeki host'lara gönderilir. - Kayıt garantisi: API'den tetiklenen analizde sonuç PostgreSQL'e
yazılamazsa görev
tamamlandideğilhataolur (CLI ise haritayı yine üretir, sadece uyarır). - WebSocket:
API_ANAHTARIsunucuda tanımlı değilse/ws/uyarilarde bağlantıyı reddeder (REST ile aynı "kapalı başla" davranışı). İşçi başka bir süreçte çalışabildiği için canlı uyarılar PostgreSQLNOTIFYile (turbulans_uyarilarikanalı) API'ye gelir ve oradan istemcilere iletilir.
Bilinçli olarak eklenmedi: veri_indirme.py'nin gerçek ERA5 indirmesini
tetikleyen bir uç nokta (rate-limit/ban riski), JWT/OAuth2 kullanıcı girişi
(tek kullanıcılı/dahili bir araç için statik anahtar yeterli görüldü, çok
kullanıcılı bir sürüme geçilirse yükseltilebilir).
uvicorn turbulans_radar.api.api_servisi:app --reload --port 8000
# tarayıcıda aç: http://localhost:8000/harita/harita3d.htmlweb/harita3d.html, build aracı gerektirmeyen tek dosyalık bir MapLibre GL
JS sayfasıdır -- api_servisi.py tarafından API ile AYNI origin'de sunulur
(app.mount("/harita", ...)), bu yüzden fetch()/WebSocket çağrıları
CORS'a takılmaz. Sayfaya uçuş numarası, tarih ve API anahtarını (bir kez
girilir, localStorage'da tutulur) yazıp "Yükle"ye basman yeterli:
- Rota,
GET /api/v1/ucuslar/{ucus}/{tarih}'ten çekilip TI1 şiddetine göre renklendirilmiş noktalar + çizgi olarak "globe" (3D küre) projeksiyonunda gösterilir; alttaki zaman kaydırıcısı ile rota an be an oynatılabilir. GET /api/v1/ucuslar/{ucus}/{tarih}/sigmet-dogrulama'dan gelen gerçek SIGMET poligonları (varsa) sarı bir katman olarak haritaya eklenir./ws/uyarilar'a bağlanıp, bir analiz sırasında orta-şiddetli türbülans tespit edilirse ekranda anlık bir uyarı (toast) gösterir.- Harita karosu (tile),
harita.py'de daha önce yaşanan "CartoDB anahtar istemeye başladı" sorununu tekrarlamamak için YİNE anahtarsız Esri World Street Map'i kullanır; MapLibre CDN sürümü (5.8.0) BİLEREK sabitlendi (daha yeni sürümler -- 6.x -- klasik<script>ile çalışan UMD paketini kaldırıp sadece ES module dağıtıyor).
Bu sayfa gerçek bir tarayıcıda (Playwright + headless Chromium) uçtan uca
test EDİLDİ: gerçek bir uçuş (THY322, 2019-01-15, 1614 nokta) analiz edilip
sayfaya API anahtarıyla yüklendi, rota/TI1 renklendirmesi/zaman kaydırıcısı
render oldu (bkz. yukarıdaki ekran görüntüsü niteliğindeki doğrulama). Bu
test GERÇEK bir hata ortaya çıkardı ve düzeltildi: harita.setProjection
metodu, önceden sabitlenen MapLibre 4.7.1'de YOKTU (kod içi yorum bunun
var olduğunu YANLIŞ varsayıyordu) -- 5.8.0'a geçildi. Ardından
setProjection'ı Map constructor'ından hemen sonra çağırmanın "Style is
not done loading" hatası verdiği görüldü; "globe" projeksiyonu artık
doğrudan constructor'ın projection seçeneğine taşındı, harita.on("load", ...) içinde bir savunmacı ikinci deneme daha bırakıldı.
Görünüm araçları (fikirler hook-365/adsb-3d ve kevtoe/worldview'dan, kod alınmadı):
- 3B harita: seviye bandı (FL) filtresi ve "yalnız seyir (FL280–FL420)" kısayolu; zaman kaydırıcısında gerçek zaman damgalarıyla oynatma (60×/300×/1200×).
- Rota simülasyonu: SIGMET ve kısıtlı saha hacimleri için seviye bandı filtresi; Pareto seçeneklerinden önerilmeyenler kesikli gri çizgiyle çizilir.
- Filtreler yalnızca görünümü değiştirir; rota hesabı tüm kısıtlarla yapılır.
rota/a_yildiz.py'deki A* araması (rota_optimizasyonu.py çağırır), maliyetini takılabilir risk
katmanlarından (risk_katmanlari.py) alır. Her katman aynı düğüm/kenar
grafı için yasak düğüm/kenarlar (SERT kısıt) ve saniye cinsinden cezalar
(YUMUŞAK kısıt) üretir; yeni bir risk kaynağı eklemek A*'ı değiştirmez:
| Katman | Tür | Kaynak |
|---|---|---|
Ti1CezaKatmani |
yumuşak (ceza) | ERA5'ten hesaplanan Ellrod TI1 >= TI1_ESIK_ORTA_SIDDETLI |
SigmetKisitKatmani |
sert (yasak) | Canlı AWC SIGMET'leri (sigmetler tablosu) |
KisitliSahaKatmani |
sert (yasak) | Çatışma bölgeleri, P/R/D sahaları, NOTAM'lı geçici kısıtlar (kisitli_hava_sahalari tablosu) |
SIGMET kısıtı dört boyutludur: yatay poligon + irtifa bandı (taban_ft/
tavan_ft, boş taban = yerden) + uçağın o noktaya VARIŞ zamanında
geçerlilik. Kenar kontrolü, iki ızgara düğümü arasındaki bacağın poligonu
kesip kesmediğine de bakar (seyrek ızgarada küçük bir SIGMET "atlanmasın").
Poligona yanal ve dikey tampon eklenir: TS/CONVECTIVE 20 NM, TURB/MTW
10 NM, diğer türler 10 NM, tehlikesi bilinmeyen en büyük tampon; taban altı
ve tavan üstü 1000 ft (SIGMET_YANAL_TAMPON_NM, SIGMET_DIKEY_TAMPON_FT).
Bunlar parametrik varsayımdır, kalibre edilmedi; uygulanan tampon
yanıtta sigmet_kontrolu.tampon ve SIGMET başına yanal_tampon_nm ile
raporlanır. Varsayılan kaçınılan tehlikeler: TURB, MTW, TS, CONVECTIVE, VA, TC
(SIGMET_KACINILACAK_TEHLIKELER). Öncelik sırası: (1) SIGMET'e girmemek,
(2) TI1 riskinden kaçınmak, (3) en ucuz yakıt/süre. SIGMET'e girmeyen hiçbir
rota bulunamazsa (örn. varış noktası SIGMET içinde) sistem öneri yapmaz:
guvenli_rota_bulundu_mu: false ve açıklamada "ÖNERİ YOK". SIGMET kısıtı
hava verisinden bağımsızdır -- ERA5 kapsamı dışında da (rüzgarsız, TAS ile)
uygulanır. Yanıttaki sigmet_kontrolu alanı kontrolün durumunu
(uygulandi / aktif_sigmet_yok / erisilemedi), uygulanan SIGMET'leri ve
canlı hesapta son çekim SIGMET_BAYATLIK_DAKIKA'dan eskiyse bayat_mi
uyarısını taşır; CZML çıktısı SIGMET'leri 3D sahnede yarı saydam kırmızı
hacimler olarak çizer.
Canlı veri: sigmet_saglayici.py, aviationweather.gov'un iki uç noktasını
(airsigmet: ABD iç, isigmet: uluslararası -- Ankara FIR/LTAA dahil)
normalize edip sigmetler tablosuna upsert eder; akıştan düşen (iptal
edilen) SIGMET'lerin geçerliliği sona erdirilir, süresi dolanlar
SIGMET_SAKLAMA_GUN sonra silinir. Yenileme yolları: POST /api/v1/sigmet/guncelle (n8n Schedule Trigger, örn. 10-15 dk),
turbulans-sigmet (cron) ya da SIGMET_OTOMATIK_GUNCELLEME_DAKIKA
0 ile API'nin kendi zamanlayıcısı.
Sessiz kayıp koruması: "akışta yok → sonlandır" kuralı, akış
çözümlenemediğinde tüm aktif SIGMET'leri hata vermeden kapatabilirdi (örn.
AWC coords alanını yeniden adlandırsa). Bu yüzden her akış önce denetlenir:
boş ya da liste olmayan yanıt veya SIGMET kayıtlarının
SIGMET_MAKS_COZUMLENEMEYEN_ORAN'dan (varsayılan %25) fazlasının
çözümlenememesi kaynak hatası sayılır. Bu durumda mevcut kayıtlar
sonlandırılmaz, kaynak_hatalari alanı doldurulur ve kaynak "başarılı
güncelleme" almaz. Her kaynağın son deneme/son başarılı çekimi
veri_kaynagi_durumlari tablosunda tutulur; bayat_mi artık en eski son
BAŞARILI çekime bakar ve açıklama hata veren kaynağı adıyla belirtir. Aynı
denetimde canlı akışta sessizce atılan bir biçim de bulundu: geom: "AREAS"
(tek SIGMET'te birden fazla poligon) artık alan başına bir kayıt olarak
saklanıyor. Okunamayan irtifa değeri daha geniş bir yasak banda, okunamayan
tehlike türü BILINMIYOR'a çevrilir ve bu tür SIGMET'lerden her zaman
kaçınılır.
Koordinatsız SIGMET'ler (FIR yedeği): AWC bazı SIGMET'leri ("ENTIRE FIR"
ya da metinle tarif edilmiş, koordinat listesi boş gelen alanlar) hiç poligon
vermeden yayınlıyor -- bunlar eskiden sessizce elenip A* tarafından hiç
görülmüyordu. veri/fir_sinirlari.py, VATSIM'in FIR sınır verisiyle
(turbulans-statik indirir; bkz. Kurulum) bu SIGMET'i FIR'ın TAMAMINA
genişletir -- kısmi bir alanı FIR'a büyütmek, hiç uygulamamaktan daha
muhafazakârdır. FIR bilinmiyorsa (sınır verisi yoksa ya da kod eşleşmiyorsa)
eski davranış (eleme) korunur. Bu genişletmeler _akis_sagligini_denetle
tarafından da "çözümlenemeyen" gibi sayılır -- AWC koordinatları TOPTAN
kaldırırsa (madde 1'in koruduğu senaryo) FIR yedeği bunu maskeleyip akışı
"sağlıklı" göstermez.
A*'ın yanal ızgarası büyük daireden 400 km'ye kadar sapabildiği için, hava
durumundan kaçarken planlı rotanın hiç kullanmadığı bir çatışma bölgesine ya
da yasak sahaya rota önerebiliyordu. KisitliSahaKatmani bu alanları SIGMET
ile aynı dört boyutlu mantıkla (poligon + irtifa bandı + geçerlilik penceresi)
sert kısıt olarak uygular; boş geçerlilik sınırı süresiz, boş taban/tavan
yer/sınırsız demektir. Öncelik sırası: (1) SIGMET'e ve kısıtlı sahaya
girmemek, (2) TI1 riskinden kaçınmak, (3) en ucuz yakıt/süre.
- Uç nokta koridoru: kalkış ya da varış noktasını İÇEREN sahada (örn.
varış ülkesi) uçuşun planlı rotasına yetkili olduğu varsayılır: sadece
büyük dairenin ±
KISITLI_SAHA_UC_KORIDORU_KM(100) km çevresi serbest, sahanın geri kalanına sapma önerilmez. Bu sahalarmuaf_tutulanlar'da raporlanır. - Gerçek veri (openAIP):
OPENAIP_API_ANAHTARI(openaip.net'ten ücretsiz) tanımlıysaturbulans-kisitli-saha openaip --ulke TRya daPOST /api/v1/kisitli-sahalar/openaip(yönetici, kuyruğa girer) ülkenin AIP'ten derlenmiş Restricted/Prohibited sahalarını çeker (OPENAIP_SAHA_TURLERIile Danger/TRA/TSA eklenebilir) veopenaipkaynağını tam yeniler; boş yanıt mevcut veriyi silmez. Alanlar resmi OpenAPI şemasından doğrulandı; FL/metre limitleri feet'e çevrilir, zemine göre (AGL) üst limitlere arazi payı eklenir, NOTAM'la etkinleşen sahalar sürekli etkin sayılır. Lisans: openAIP verisi CC BY-NC 4.0 (ticari olmayan kullanım, atıf; tüm kaynaklar için bkz. docs/VERI_KAYNAKLARI_VE_LISANSLAR.md). Herkese açık dışa aktarım dosyaları artık anahtarsız indirilemiyor. - Otomatik yenileme:
OPENAIP_OTOMATIK_GUNCELLEME_SAAT> 0 ise API bu aralıkla yenilemeyi işçi kuyruğuna ekler (son denemeye göre; bekleyen bir openAIP görevi varsa eklemez, birden fazla API kopyası çoğaltmaz). Her denemeveri_kaynagi_durumlari'na yazılır; iki aralık boyunca başarı yoksa/saglik?derin=truekısıtlı sahalarıbayatraporlar. Alternatif: n8n. - Üretim profili:
.env.uretim.example-- örnek veri kapalı (KISITLI_SAHA_ORNEK_VERI_YUKLE=false), openAIP günlük, SIGMET 10 dk, işçi ayrı serviste, kişi başına anahtarlar. - Veri: GeoJSON FeatureCollection (Polygon/MultiPolygon;
kimlik,ad,tur=CATISMA/YASAK/KISITLI/TEHLIKELI/GECICI,taban_ft,tavan_ft,baslangic,bitis,aciklama). İçe aktarma:turbulans-kisitli-saha ice-aktar sahalar.geojson --kaynak aipya daPOST /api/v1/kisitli-sahalar?kaynak=notam(n8n bir NOTAM akışından geçici kısıtları bu uçla iter). İç halkalar (delikler) muhafazakâr olarak yok sayılır. - Aktivasyon zamanları (askerî sahalar): Bir saha geçerlilik süresi içinde
yalnızca belirli zamanlarda aktif olabilir.
aktif_araliklarNOTAM ile duyurulan aktivasyonları ([{"baslangic": "...Z", "bitis": "...Z"}]),haftalik_takvimAIP'teki "MON-FRI 0600-1500" türü takvimi tutar ([{"gunler": ["PZT", "CUM"], "baslangic": "06:00", "bitis": "15:00"}], UTC; bitiş başlangıçtan küçükse gece yarısını aşar). İkisi de yoksa saha her zaman aktiftir. A*, uçağın o noktaya varış zamanı (± belirsizlik payı) aktif bir zamana denk geliyorsa sahayı yasak sayar. - Örnek veri: paketle gelen
ornek_kisitli_sahalar.geojson, Natural Earth 1:50m (kamu malı) ülke sınırlarından Suriye ve Irak'ı "çatışma bölgesi" olarak içerir.KISITLI_SAHA_ORNEK_VERI_YUKLE=true(varsayılan) iken API açılışında, tabloda bu kaynaktan kayıt yoksa yüklenir. Resmi FIR/CZIB sınırı değildir; yanıt açıklaması örnek veri kullanıldığını belirtir. Gerçek kullanımda kapatılıp güncel AIP ENR 5.1, EASA CZIB ve NOTAM verisi aktarılmalıdır. - Örnek: Malatya → Musul (FL340): büyük daire Suriye'nin kuzeydoğu ucunu 13 nokta/bacakta kesiyor; A* 60 km yanal sapmayla Suriye'ye girmeyen rotayı buluyor, Irak varış ülkesi olduğu için muaf. Koridoru tamamen kesen bir saha varsa sistem "ÖNERİ YOK" der.
- 3D simülasyonda kısıtlı sahalar mor yarı saydam hacimler olarak çizilir.
Doç. Dr. Fulya Aybek Çetek'in önerileri ve proje ekibinin analizi: docs/hoca_geri_bildirim_analizi.md.
- Kapsam ve kullanım zamanı:
- Her rota yanıtı
kapsam(yalnız seyir safhası, ToC–ToD) veplanlama_ufku(geçmiş analiz ya da uçuş öncesi planlama, kalkışa kalan saat) taşır. - Uçuşun SIGMET yayın ufkunun (4 sa) ötesindeki kısmı için
sigmet_ufuk_disiuyarısı verilir.
- Her rota yanıtı
- FRATURK serbest rota ağı:
POST /api/v1/simulasyon/rotagövdesinde"arama_uzayi": "ats", ya da arayüzde "Arama uzayı → FRATURK serbest rota (FL305+, 20:00–02:00 UTC)".- Rota,
ats_verisi/ats_agi.jsonağında graf tabanlı A* ile aranır. Ağ, AIP Türkiye ENR 4.4 noktaları ve ENR 4.1 VOR/NDB'lerindenturbulans-aip-atsile kurulur ve yalnız FRA DCT kenarlarından oluşur; ATS yolları (ENR 3.1/3.2) ağda yoktur. Depoya konmaz: docs/veri_hazirlama/ATS_AGI_HAZIRLAMA.md. - Ağ yoksa istek 400 döner. Varsayılan
koridormodu değişmedi. - Ağ otomatik hazırlanabilir:
turbulans-aip-ats --indir(AIP Türkiye ENR 4.4, FL305–FL660 FRA). Kısıtlı sahalar içinturbulans-aip-sahalar --indir(ENR 5.1). - FRA yalnızca AIP ENR 1.3'teki saatlerde (20:00–02:00 UTC, AIRAC 01/26) kullanılır. Her FRA kenarına girişin pencere içinde, kenar sonuna varışın (belirsizlik payıyla) 02:00'den önce olması gerekir (§5.5.2.1); olmuyorsa ATS modu nedenini söyleyen 400 döner.
- İsteğe bağlı
kalkis_meydani/varis_meydani(ICAO): ToC/ToD o meydanın AIP FRA bağlantı noktalarına (D/A) bağlanır, ör. LTCI → DYB/EZS/ERZ. Verilmezse ToC yalnız D/E, ToD yalnız A/X rollü noktalara (FIR içinde önce D/A) bağlanır; her iki durumda daats.uyarilarneyin yaklaşık olduğunu söyler. DCT kenarları FIR içinde ve sınıra 5 NM'den uzak kalmalı (§5.2.1.6, §5.2.5); sınır VATSIM'in yaklaşık çizimidir.
- Ayırma göstergesi:
turbulans-ayirma UCUS TARIH [--sorgu-izni].- Gerçek iz, büyük daire ve önerilen rota; aynı zaman penceresinde uçmuş trafiğin ADS-B izleriyle karşılaştırılır.
- Minimalar varsayımdır: yatay 5 NM, dikey 1000 ft.
- Yalnızca göstergedir; rota kararına girmez.
- OpenSky'a uçuş başına en fazla bir sorgu gider (en fazla 3 saatlik pencere, 10 sn örnekleme); varsayılan yalnızca önbelleği okur.
ERA5 bir reanalizdir, birkaç gün gecikmeyle yayınlanır -- "şimdi" için rota
çizemez. veri_saglayicilari.py bu yüzden hava verisini kaynaktan bağımsız
bir Veri Sağlayıcı arayüzüyle alır; her sağlayıcı küpü ERA5 ile AYNI
ortak şemaya (u/v/t, valid_time, pressure_level hPa, boylam -180..180)
normalize eder, böylece eşleştirme, risk katmanları ve A* kaynağı bilmez.
- Seçim sırası (
veri_kupunu_sec): önce yerel arşiv küpleri (ERA5); hiçbiri noktaları kapsamıyorsa ve zaman canlı penceredeyse (şimdi -CANLI_GECMIS_SAAT/ +CANLI_TAHMIN_UFKU_SAAT) canlı sağlayıcı; ikisi de yoksaNone(uydurma veri yok). Rota simülasyonu,/turbulans/tahminve son 48 saatteki uçuş analizleri bunu kullanır; yanıttakiruzgar_verisi_kaynagigfs_tahmin/era5_gercek/era5_kapsam_disiolur. GfsThreddsSaglayici: NOAA GFS 0.25°, UCAR THREDDS NetCDF Subset Service'ten her basınç seviyesi (varsayılan 200/250/300 hPa) paralel ayrı istekle NetCDF olarak alınır -- GRIB2/ecCodes gerektirmez (ecCodes'un Windows/Python 3.14 için hazır paketi yok). Türkiye bölgesi, 3 seviye, birkaç saatlik pencere: ~250 KB, ~15 sn.- Katalog ve yeniden kullanım: indirilen küp
CANLI_VERI_KLASORU'na yazılır,hava_durumu_kupleritablosuna kaydedilir (kup_katalogu.py); aynı bölge/zamanı kapsayan veCANLI_KUP_TAZELIK_SAATiçinde indirilmiş bir küp varsa yeniden indirilmez. GeçerliliğiCANLI_KUP_SAKLAMA_SAATönce bitmiş canlı küpler (dosya + kayıt) otomatik silinir. - Önceden ısıtma:
POST /api/v1/veri/canli/hazirla(örn. n8n her GFS döngüsünden sonra sık kullanılan bölgeler için) ilk rota isteğinin indirme süresini beklemesini önler. - Yeni bir sağlayıcı (örn. ECMWF Open Data -- GRIB2, Docker/Linux'ta)
VeriSaglayiciarayüzünü uygulayarak eklenir.
- Seçim katalogdan: noktaları kapsayan yerel küp, dosyalar açılmadan
hava_durumu_kuplerikataloğundan (bölge/zaman kesişimi) bulunur; sadece aday küpler yüklenir. Katalogda henüz olmayan dosya ya da veritabanına erişilemediğinde dosyanın yalnızca koordinatları okunur (önbellekli). Eskiden ilk seçimde TÜM yerel küpler belleğe yükleniyordu (16 küp, 92 MB). - Pencereli okuma:
KUP_TAM_YUKLEME_ESIGI_MB'den (256) büyük küplerden sadece noktaların çevresi okunur (rota için A* koridoru kadar pay, eşleştirme için 1°; 1° ve 6 saatlik sınırlara hizalı). İzmir-Van rotası için pencere 1.2 MB (tüm Türkiye küpü 69 MB); TI1 sonuçları tam küple birebir aynı (testle doğrulanıyor). - Bütçeli önbellek: yüklenen tüm küp/pencereler
KUP_ONBELLEK_MAKS_MB(2048) bütçeli bir LRU önbellekte; bütçe aşılınca en uzun süre kullanılmayan atılır (eskiden hiçbir küp atılmıyordu). NetCDF/HDF5 erişimi (okuma, GFS yazma) tek kilitle sıraya alınır; önbellek isabetleri yüklemeyi beklemez.
rota_backtest.py, analiz edilmiş her uçuşun gerçek izini (OpenSky, gerçek
irtifasıyla) aynı giriş/çıkış noktaları için büyük daire ve A*
rotasıyla AYNI ölçütle karşılaştırır: gerçek iz, diğer rotalarla aynı nokta
sayısına kümülatif mesafe boyunca yeniden örneklenir; TI1 aynı hava küpüyle
ve aynı kodla hesaplanır; aktif SIGMET ihlalleri aynı katmanla sayılır.
Karşılaştırma, hava küpünün kapsadığı en uzun kesintisiz seyir bloğu
üzerinde yapılır (15 dk'dan uzun veri boşluğu bloğu böler -- OpenSky
kapsamasının olmadığı bölümler uydurma bir rotayla doldurulmaz). Sonuçlar
rota_backtestleri tablosuna yazılır (uçuş başına en son çalıştırma);
GET /api/v1/backtest filo geneli özeti döner; komut satırından
turbulans-backtest --hepsi. Ölçümler artık irtifayı da
saklıyor (edr_olcumleri.irtifa_m).
Depodaki gerçek uçuşla (15 Ocak 2019, Türkiye ERA5 küpü, A320 profili; 6 Ekim 2026'da yasal FL kuralı ve çevreleyen katman fiziğiyle yeniden üretildi) -- riskli oran: TI1 >= eşik nokta oranı. Büyük daire ve A* rotası, gerçek seyir irtifasının bu yöndeki en yakın yasal FL'sinde hesaplanır:
| Uçuş | Seyir (gerçek → yasal) | Karşılaştırılan bölüm | Riskli oran (gerçek / büyük daire / A*) | A* stratejisi |
|---|---|---|---|---|
| THY322 | FL300 → FL290 (doğu) | 116 km | 0.19 / 0.32 / 0.00 | yanal (+0,4 dk) |
Bu satır 6 Ekim ölçümüdür (TI1 eşiği 7e-7 olmadan önce). Güncel değer 7e-7 eşiğiyle
0,24 / 0,39 / 0,02'dir: docs/sonuclar/2026-10-18/SAYILAR.md backtest[1].
Önceki tablodaki THY72C ve THY606 veritabanında artık olmadığı için yeniden üretilemedi; eski değerleri (basınç seviyesinden türetilen dikey alternatifler, eski fizik) geçersiz sayılmalıdır.
Yukarıdaki "riskli oran" döngüseldir: A* rotası TI1'i düşürecek şekilde
seçiliyor, başarı da yine TI1 ile ölçülüyor. Bu yüzden her backtest ayrıca
A*'ın ve TI1 hesabının hiç görmediği gerçek dünya kanıtıyla ölçülür
(dogrulama/bagimsiz_kanit.py); kaynak bir uçuşu kapsamıyorsa değer None
kalır, "sıfır" sayılmaz:
| Kaynak | İçerik | Kapsam |
|---|---|---|
sigmet_arsivi |
Sistemin kendi SIGMET arşivi (sigmetler), TURB/MTW |
Küresel (Türkiye dahil), arşivin başladığı andan itibaren, SIGMET_SAKLAMA_GUN geriye |
iem_sigmet |
IEM'in AWC SIGMET arşivi (2005-) | ABD sorumluluk sahası |
iem_pirep |
IEM PIREP/AIREP arşivi; rota tüpünde (50 km, ±2000 ft, ±1 sa) türbülans raporları ve orta ve üstü (MOG) olanlar | Pratikte Kuzey Amerika + Kuzey Pasifik |
Bağımsızlık için A* backtest'te TURB/MTW SIGMET'lerini görmez (oraj,
volkanik kül, tropikal siklon SIGMET'leri ve kısıtlı sahalar sert kısıt
olarak kalır). MOG tanımı ML etiketleriyle aynıdır (1254 etiketli PIREP'te
ikili sınıflama %100 örtüşüyor). Sonuçlar *_turb_sigmet, *_pirep_raporu,
*_mog_pirep ve kanit_kaynaklari sütunlarında; filo özeti azalan/artan
maruziyetli uçuş oranlarını verir.
- 2019 Türkiye uçuşları için hiçbir kaynak kapsama sağlamıyor (IEM'in "Türkiye" kutusundaki PIREP'leri yanlış konumlanmış ABD raporları) -- kanıt alanları dürüstçe boş.
- Canlı örnek (26 Eylül 2026): OpenSky'dan alınan gerçek bir uçuş (PUE502, FL350, Brezilya, 1744 km'lik seyir) canlı GFS ile analiz edilip backtest edildi; sistemin kendi arşivindeki aktif TURB SIGMET'lerine maruziyet (nokta + bacak): gerçek iz 30, büyük daire 28, A* 33. GFS tabanlı TI1 aynı bölgede hiç riskli nokta görmedi (üç rotada da 0.00). Yani bu uçuşta TI1 katmanı, tahmincilerin FL340-410 için yayınladığı türbülansı yakalayamadı -- döngüsel ölçümün gizleyeceği bir kör nokta. Canlı sistemde bu SIGMET'lerden sert kısıt olarak yine kaçınılır; backtest yalnızca TI1'in bağımsız becerisini ölçer. A*'ın 28'den 33'e çıkması, backtest'te TURB/MTW SIGMET'lerini görmeyen ve TI1'de risk bulmayan A*'ın rotayı başka bir ölçütle (süre/rüzgâr ya da kalan sert kısıtlar) ayırıp SIGMET alanında daha uzun kalmasından gelir; hangi ölçüt olduğu, kayıt veritabanında kalmadığı için yeniden üretilemedi.
- Bu bulgu tek bir uçuşla sınırlı kalmayıp her rota yanıtına taşınır:
POST /simulasyon/rotavePOST /turbulans/tahminyanıtlarında ayrı birti1_guvenilirlik_notualanı (fizik/turbulans_indeksleri. TI1_GUVENILIRLIK_NOTU) her zaman bulunur ve iki web arayüzünde de gösterilir -- TI1'in tek başına doğrulanmadığı bir dipnot olarak değil, arayüzün elinin altında bir uyarı olarak.
Karşılaştırılan bölümler kısa: THY322'nin OpenSky izinde Doğu Anadolu'da
65 dk'lık bir veri boşluğu var; THY606 (İstanbul-Kahire) ve THY72C
(İstanbul-Dakar) küpün dışına çıkıyor. Filo özeti, n8n ile daha çok uçuş
analiz edildikçe (POST /api/v1/backtest/toplu) anlamlı hale gelir. N10VZ
(Teksas) küp dışında olduğu için dürüstçe atlanır.
uvicorn turbulans_radar.api.api_servisi:app --reload --port 8000
# tarayıcıda aç: http://localhost:8000/harita/ucus_simulasyonu.htmlweb/ucus_simulasyonu.html, web/harita3d.html ile AYNI desende (tek
dosyalık, build aracı yok, api_servisi.py API ile aynı origin'den sunar)
ama CesiumJS tabanlı bir 3D küre sayfasıdır. Başlangıç/bitiş enlem-boylamı,
irtifa, tarih-saat ve uçak modelini girip "Simüle Et"e basınca:
POST /api/v1/simulasyon/rota(bkz.rota_optimizasyonu.py) iki GERÇEK rota hesaplar: normal rota (iki nokta arası büyük daire) ve optimize rota. Optimize rotanın önceliği ÖNCE GÜVENLİK, SONRA MALİYET:- Normal rota üzerinde, projenin ANA analiz koduyla (Ellrod TI1 --
eslestirme.py/turbulans_indeksleri.py, gerçek ERA5 verisiyle) riskli türbülans var mı bakılır. - Riskli türbülans YOKSA, optimize rota normal rotayla birebir aynıdır -- uydurma bir sapma gösterilmez.
- Riskli türbülans VARSA, adım 3'te açıklanan A* (A-star) graf araması o bölgeyi TAMAMEN atlatan, ERA5 rüzgarına göre de en ucuz olan yolu bulur; ızgarada riski tam ortadan kaldıran bir yol yoksa, riski en aza indiren yol dürüstçe seçilir ("tamamen güvenli" diye yalan söylenmez).
- Bu sıralamanın nedeni: türbülansın kendisi doğrudan çok fazla yakıt yaktırmaz (asıl yakıt belirleyicisi rüzgardır) -- türbülanstan kaçınmak genelde yol uzatıp FAZLADAN yakıt gerektirir (gerçek uçuşlarda da böyle); değeri güvenlik/konfordur. Bu yüzden "optimize rota her zaman ucuzdur" varsayılmaz, sonuç panelinde bazen "ekstra yakıt: güvenlik için sapmanın bedeli" olarak dürüstçe gösterilir.
- Normal rota üzerinde, projenin ANA analiz koduyla (Ellrod TI1 --
- A* araması (bkz.
_a_yildiz_ile_rota_ara): Büyük daire etrafında, rotaya dik yönde kaydırılmış aday konumlardan oluşan bir IZGARA kurulur (bkz._YanalIzgara); ızgaranın her düğümünün TI1'i projenin ana analiz koduyla (eslestirme.py) tek bir vektörel çağrıda hesaplanır. Her kenarın maliyeti gerçek ERA5 rüzgarına göre uçuş süresi + (riskli türbülans içeriyorsa) büyük bir ceza olarak tanımlanır; A*, kalan mesafe tabanlı admissible (asla aşırı tahmin etmeyen) bir sezgiselle başlangıçtan bitişe TOPLAM MALİYETİ EN AZA indiren yolu garantili optimal şekilde bulur. Erken sürümde ızgara çok kaba (100 km/adım) olduğu için A*'ın rotanın hemen başında/sonunda ani bir sıçrama yapıp onu koruduğu (eski, daha basit "birkaç aday dene" yaklaşımından bile daha uzun bir rota) gerçek veriyle tespit edildi -- ızgara inceltilip (20 km/adım) başlangıca/bitişe yakın erişilebilir sapma bir "zarf" ile kademelendirilerek düzeltildi. - Sapma sınırları mesafe ve açıyla tanımlı: sabit "20 km/adım" kısa
rotada gerçek dışı keskin sapmalara (480 km'lik İstanbul-Antalya'da 12
km'lik bacakta 59°), uzun rotada gereksiz dar koridora (8000 km'lik
İstanbul-New York'ta kalkıştan 600 km sonra en fazla 60 km -- SIGMET'lerden
kaçılabilecekken "öneri yok") yol açıyordu. Artık her bacağın büyük daire
yönüne göre açısı en fazla
ROTA_MAKS_SAPMA_ACISI_DERECE(30°), toplam sapma en fazlaROTA_MAKS_YANAL_SAPMA_KM(400 km); ızgara aralığı en fazlaROTA_YANAL_IZGARA_KM(20 km), kısa rotada açı sınırına göre daralır. Ölçümler (İzmir-Van, ERA5 TI1 + 50 SIGMET): A* 58 ms, tam rota kararı 0.29 sn; İstanbul-New York (1481 düğüm, 18 büyük SIGMET): A* 70 ms, en dik bacak 16.7°, 140 km sapmayla güvenli rota. - Çok faktörlü karşılaştırma -- irtifa değişimi (tırmanma/alçalma):
Riskli türbülanstan kaçınmanın YANAL sapma dışında ikinci bir GERÇEK
stratejisi daha var: aynı yatay rotada kalıp aynı yönün bir üst/alt yasal
uçuş seviyesine geçmek (bazı CAT katmanları irtifaya bağlıdır). Seviyeler
yarım daire kuralından gelir (
rota/ucus_seviyeleri.py: manyetik iz 000–179° tek, 180–359° çift FL; RVSM'de 2000 ft, FL410 üstünde 4000 ft; manyetik sapma sabit +5°E VARSAYIM; tip tavanıazami_fl). Kurala aykırı girilen seviye en yakın yasal FL'ye yuvarlanır ve yanıtta uyarı verilir. Rüzgâr ve TI1 o FL'ye en yakın / çevreleyen basınç seviyesinden okunur; yer hızı rüzgâr üçgeniyle (GS = √(TAS² − Xw²) + Hw) hesaplanır. Seyir başı ve sonu planlanan seviyede olduğu için geçici seviyeye gidiş ve planlanan seviyeye dönüş birlikte maliyetlenir (bir tırmanma + bir alçalma, 1500 ft/dk). Yakıt varsayılan olarak OpenAP ile hesaplanır (rota/performans_modeli.py): yakıt akışı kütleye, TAS'a, irtifaya ve düşey hıza bağlıdır, kütle seyir boyunca azalır, alçalış kredi verir; NOx da hesaplanır. Seyir başı kütlesi MTOW xROTA_SEYIR_KUTLE_ORANI(0,85, kalibre edilmedi). Daha yüksek seviye bu yüzden daha az yakıt gösterebilir.ROTA_YAKIT_MODELI=sabiteski tabloya döner (tırmanmada +%50, alçalmaya kredi yok; seviyeye bağlı seyir yakıt akışı yok). TAS iki modelde de sabittir.rota_simulasyonu_olustur, yanal A* yolu ile irtifa değişimi adayları arasından TOPLAM maliyeti (seyir yakıtı + seviye geçiş bedeli) en düşük, güvenliği sağlayan seçeneği seçer. Seçilen strateji (kacinma_stratejisi: "yanal"/"irtifa_yukari"/"irtifa_asagi") ve optimize rotanın kendi irtifası (irtifa_ft) yanıtta ayrı alanlar olarak döner; sonuç panelinde de gösterilir. - Her iki rota, gerçek bir 3D uçak modeliyle (
web/models/ucak.glb-- CesiumJS'in kendi resmi örnek verisi, Apache 2.0 lisanslı) zaman-senkronize CZML animasyonu olarak sahneye eklenir (mavi = normal, yeşil = optimize); Cesium'un yerleşik zaman çizelgesi/oynatma kontrolleriyle izlenebilir. - Sonuç panelinde süre, mesafe, tahmini yakıt, tahmini CO2 emisyonu
(
CO2_KG_PER_KG_YAKIT = 3.16-- ICAO/IPCC'nin standart, halka açık jet yakıtı emisyon katsayısı) VE riskli türbülans nokta sayısı (normal vs optimize) ayrı ayrı karşılaştırılır. - Dinamik rota güncelleme: "🔄 Uçuş sırasında yeniden hesapla" butonu, simülasyon oynarken uçağın O ANKİ (Cesium'un kendi interpolasyonuyla bulunan) konumunu yeni başlangıç noktası alıp AYNI hedefe, AYNI gerçek backend'i (A* + irtifa karşılaştırması) yeniden çağırır -- uydurma bir "canlı meteorolojik değişiklik" simülasyonu değil, gerçek bir yeniden planlama çağrısıdır.
- Kabin içi bildirim çerçevelemesi: Riskli türbülans tespit edildiğinde,
zaten var olan
/ws/uyarilarWebSocket uyarı mantığının simülasyon sayfasındaki karşılığı olarak, gerçek TI1 şiddetine dayalı (ama arayüz çerçevelemesi illüstratif) bir "kabin ekibine bildirim" mesajı gösterilir.
Kapsam/dürüstlük sınırlaması: Gerçek ERA5 rüzgar/türbülans verisi SADECE
config.HAVA_DURUMU_DOSYASI küpünün (bu depodaki varsayılan veri:
Türkiye/Doğu Akdeniz, Ocak 2019 -- enlem 36-42, boylam 26-45) ve
config.EK_HAVA_DURUMU_KLASORU'ndaki küplerin (varsayılan
era5_egitim_verisi/: Kuzeydoğu ABD, enlem 40-50, boylam -80/-70,
2018-2020'nin seçili günleri) kapsadığı bölge/tarih/irtifa için var; rotayı
en iyi kapsayan küp otomatik seçilir. İrtifa, küpün basınç seviyelerinden
(200-300 hPa) DIKEY_KAPSAM_TOLERANSI_HPA'dan (50) fazla uzaksa -- yaklaşık
FL265 altı/FL445 üstü -- kapsam dışı sayılır. Seçilen başlangıç/bitiş/tarih/
irtifa bu aralığın dışındaysa, kod
sigmet_dogrulama.py'deki AYNI ilkeyle SESSİZCE uydurma bir "iyileşme"
göstermez -- ruzgar_verisi_kaynagi: "era5_kapsam_disi" döner, iki rota da
sadece uçağın hava hızıyla (rüzgarsız/türbülanssız) hesaplanır ve arayüzde bu
açıkça belirtilir. Bu veri kümesiyle demo yapmak için başlangıç/bitiş
noktalarını bu bölgenin içinde ve tarihi Ocak 2019 içinde seçmen gerekir
(sayfa varsayılan olarak İstanbul↔Antalya, 5 Ocak 2019, 29000ft ile açılır --
bu rotada gerçek bir türbülans noktası tespit edilip tamamen atlatılıyor) --
gerçek dünyadaki uçuş rotanı/tarihini görmek istersen, kendi ERA5 veri
küpünü indirip HAVA_DURUMU_DOSYASI ortam değişkeniyle o dosyayı gösterebilirsin.
Cesium ion hesabı/token'ı GEREKTİRMEZ: harita.py/harita3d.html'de anahtarsız Esri tile'a geçilme ilkesiyle aynı şekilde, burada da Cesium'un varsayılan ion terrain/imagery'si yerine anahtarsız Esri World Street Map (imagery) + düz elipsoid (terrain) kullanılır.
Bu sayfa (diğer statik önyüzlerin aksine) gerçek bir tarayıcıda (Playwright +
headless Chromium) uçtan uca test EDİLDİ: API anahtarı girme, uçak profili
listesinin yüklenmesi, "Simüle Et"e tıklama, sonuç panelinin dolması ve
haritanın gerçekten render olması otomatik olarak doğrulandı. Bu test bir
GERÇEK hatayı ortaya çıkardı ve düzeltildi: CesiumJS 1.104+'ta Viewer'ın
imageryProvider kurucu seçeneği artık sessizce HİÇBİR KATMAN EKLEMİYOR
(deprecated) -- internetteki birçok eski örnek hâlâ bunu kullanıyor. Doğru
yol baseLayer'a bir Cesium.ImageryLayer örneği vermek (bkz. sayfadaki
kod içi not). Ayrıca viewer.flyTo(dataSource)'un, zamana bağlı (dinamik)
konumlu varlıklarda TÜM rotayı değil sadece varlığın O ANKİ tekil konumunu
kapsadığı fark edildi -- kamera artık sunucudan gelen ham koordinatlardan
hesaplanan bir dikdörtgene uçuyor, CZML'nin path özelliği de (sadece o ana
kadar uçulmuş izi gösterdiği için) ayrı, zamana bağlı olmayan statik bir ön
izleme çizgisiyle tamamlandı.
TI1/Richardson sayısı fizik FORMÜLÜNE dayanır; komisyon rubriğinin "minimum gereksinim" maddesi olarak bunun yanına, GERÇEK gözlem verisiyle etiketli, çalışan bir ML sınıflandırıcısı eklendi.
Neden bu depodaki Türkiye/Ocak-2019 verisiyle değil? Bu veri kümesi için gerçek, doğrulanmış türbülans etiketi yok (ne SIGMET -- sadece ABD hava sahası, ne PIREP/AMDAR). Uydurma etiketle model eğitmek yerine (bu tam olarak projenin başında düzeltilen "uydurma katsayı" hatasının bir versiyonu olurdu), ABD hava sahasına özgü, halka açık IEM PIREP arşivinden (mesonet.agron.iastate.edu) 2018-2020 arası gerçek pilot türbülans raporları
- eşleşen gerçek ERA5 verisi indirilip (gece işi:
ml/ml_veri_hatti.py) GERÇEK bir eğitim kümesi kuruldu:
- Güncel model
ml_ornekleritablosundaki seyir irtifası PIREP'leriyle, dondurulmuş altın test günleri ayrı tutularak eğitilir ve değerlendirilir (aşağıda "ML veri hattı ve gece otomasyonu"). İlk 167 örneklik sonuçlar hatalı veriye dayandığı için bölüm sonundaki tarihçeye taşındı. - Özellikler bilinçli olarak bölgeden bağımsız tutuldu (enlem/boylam
KASITLI OLARAK dışarıda bırakıldı -- yoksa model ABD'nin bölgesel hava
düzenine ezberler, Türkiye gibi hiç görmediği bir bölgede anlamsızlaşırdı):
ti1_indeksi,richardson_sayisi,ruzgar_hizi_ms,basinc_hpa. POST /api/v1/turbulans/tahmin, tek bir nokta için hem fizik (TI1) hem ML olasılığını karşılaştırmalı döner. Model dosyası (*.joblib) repoya DAHİL DEĞİL (üretilmiş/büyük artefakt,.gitignore) -- gece işi ya daturbulans-mlile yeniden üretilebilir. Model henüz üretilmediyseturbulans_riski_tahmin_etuydurma bir tahmin dönmez, dürüstçeNonedöner.ml_egitimi.py, seçilen modeli (*.joblib) kaydederken YANINDAturbulans_ml_modeli_bilgisi.json'ı da yazar (seçilen model adı, test metrikleri, özellik listesi, eğitim tarihi) -- bu da repoya dahil değil (üretilmiş artefakt).GET /api/v1/turbulans/model-bilgisi, bu dosyayı okuyup döner; henüz eğitilmediyseegitildi_mi: falseile dürüstçe bildirir.- Model versiyonlama/rollback: her
ml_egitimi.pyçalıştırması, aktif modelin YANINDAmodel_versiyonlari/klasörüne KALICI bir kopya + manifest kaydı bırakır (repoya dahil değil, üretilmiş artefakt).GET /api/v1/turbulans/model-versiyonlarigeçmiş TÜM versiyonları listeler,POST /api/v1/turbulans/model-versiyonlari/{versiyon_id}/aktiflestirise yeniden eğitim gerekmeden geçmiş bir versiyona döner -- örn. yeni bir eğitim çalıştırması beklenenden kötü çıkarsa.
Veri indirme ve eğitim komutları: ML veri hattı ve gece otomasyonu.
Bu bölümdeki sayılar FL feet hatalı PIREP CSV'sine dayanır (yerdeki raporlar); yalnızca tarihçe olarak tutulur, sonuç olarak kullanılmaz. Güncel değerlendirme protokolü için aşağıdaki "Aktivasyon kapısı" paragrafına bakın.
-
167 gerçek, etiketli örnek (57 pozitif orta-şiddetli+ türbülans / 110 negatif, 42 farklı gün) -- FL300-400 arası, projenin
TI1_ESIK_ORTA_SIDDETLIeşiğiyle AYNI ikili eşik felsefesiyle etiketlendi. (Önceki sürümde 179 örnek vardı; 12'si, aralıklı indirilmiş ERA5 küplerinin zaman BOŞLUĞUNA düşüp günlerce uzaktaki bir saatin havasıyla eşleşen PIREP'lerdi -- artık kapsam dışı sayılıyor.) -
Üç sınıflandırıcı (Lojistik Regresyon, Random Forest, Gradient Boosting) eğitilip recall'a göre karşılaştırıldı (accuracy değil -- havacılık güvenliğinde kaçırılan gerçek türbülans/false negative en kritik hata türüdür).
-
Değerlendirme: gün bazında gruplu 5-kat çapraz doğrulama, 5 tekrar (ortalama ± std). Aynı günün PIREP'leri aynı hava sistemine ait, birbirine çok benzer örneklerdir; eski tek rastgele %75/%25 bölme onları hem eğitime hem teste koyuyordu ve metrikleri şişiriyordu (eski rapor: RF recall 0.750 / ROC-AUC 0.843 -- gruplanmamış çapraz doğrulama da aynı ~0.84'ü veriyor, gün bazında gruplayınca ~0.66'ya iniyor). Aşağıdaki sonuçlar, modelin HİÇ GÖRMEDİĞİ günlerdeki performansıdır:
Model Accuracy Precision Recall F1 ROC-AUC Lojistik Regresyon 0.637 ± 0.033 0.473 ± 0.041 0.540 ± 0.044 0.504 ± 0.042 0.644 ± 0.043 Random Forest (seçildi) 0.655 ± 0.034 0.496 ± 0.044 0.554 ± 0.077 0.522 ± 0.053 0.656 ± 0.043 Gradient Boosting 0.607 ± 0.041 0.422 ± 0.058 0.414 ± 0.080 0.417 ± 0.067 0.558 ± 0.056 Random Forest en yüksek recall'u (57 gerçek türbülans vakasının ~%55'ini yakalıyor) nedeniyle seçildi; havacılıkta bir false negative (kaçırılan gerçek türbülans) bir false positive'den (gereksiz uyarı) çok daha pahalıya mal olur. Nihai model TÜM 167 örnekle eğitilip kaydedilir.
-
Dürüst yorum: ROC-AUC ~0.66, şansın (0.5) üzerinde ama ZAYIF bir ayırt edicilik -- 167 örnek ve ~25-30 km çözünürlüklü reanaliz verisiyle beklenen bir sınır. Karşılaştırma için aynı veride SADECE Ellrod TI1'in ROC-AUC'si 0.44 (tek başına ayırt edici değil); model, TI1 + Richardson + rüzgar + basınç birleşimiyle bundan daha iyi. Model tahmini bir karar aracı değil, fizik göstergesinin yanında ek bir işarettir.
Önemli veri hatası (2026-09-30'da bulundu): yukarıdaki 167 örneğin kaynağı
pirep_ust_seviye_siniflandirilmis.csv"FL 300-400" filtresiyle üretilmişti; ancak IEM'inFLsütunu feet cinsindendir (FL360 → 36000). Filtre bu yüzden 300-400 feet'teki (pist/son yaklaşma, windshear) raporları seçmiş,ml_egitimi.pyde bunlarıFL*100ile 30.000-40.000 ft sayıp 200-300 hPa ERA5'le eşleştirmişti. Aynı CSVEDR_OLCEKLENDIRME_KATSAYISI(0.23) kalibrasyonunda da kullanıldı. Katsayı doğru irtifalı veriyle 0.40'a yeniden kalibre edildi (aşağıya bakın); model yeni veriyle en az 60 gün eşleşince yeniden eğitilir, o zamana kadar güvenilir sayılmamalıdır. Doğru veride TI1'in tek başına ROC-AUC'si 0.69'dur (eski veride 0.44).
Eğitim verisi artık ml_ornekleri tablosunda tutulur (ml/ml_veri_hatti.py):
-
Arşiv:
ML_PIREP_ARSIV_KLASORU(varsayılanpirep_ham/, Docker'da/veri/pirep_ham) içindeki ham IEM CSV'lerinden seyir irtifasındaki (ML_MIN_IRTIFA_FT-ML_MAKS_IRTIFA_FT, varsayılan 28.000-42.000 ft) ve türbülans alanı dolu PIREP'ler alınır; gün başına en fazlaML_GUNLUK_MAKS_PIREP(100) örnek, sabit tohumla rastgele seçilir. Arşiv dosyaları değişmedikçe ikinci kez okunmaz. -
Yeni PIREP (artımlı): IEM'den imleçten (
ML_IEM_BASLANGIC, sonraveri_kaynagi_durumlari'ndakiml_iem_pirepkaydı) başlayarak gün gün, gece başına en fazlaML_IEM_GECELIK_MAKS_GUNgün, ERA5'in yayınlandığı güne kadar çekilir. Hata olursa imleç ilerlemez, sonraki gece aynı günden devam edilir. Eşleşme bekleyen PIREPML_IEM_MAKS_BEKLEYEN'i (5000; 0 = sınırsız) aşarsa o gece IEM'e hiç gidilmez: gece ~300-800 eşleşme yapılırken kuyruğu büyütmek yalnızca gereksiz dış istek olur. -
Eşleştirme: bekleyen PIREP'ler gün ve boylama göre hacim sınırlı (
ML_GRUP_MAKS_HUCRE_SAAT) gruplara ayrılır; her grup için CDS'ten tek saatlik bir ERA5 dilimi indirilip özellikler çıkarılır. Maliyet PIREP değil grup sayısıyla ölçeklenir; günler mevsimlere yayılan sabit karışık sırayla işlenir. Başarısız grupML_MAKS_DENEMEgeceye kadar yeniden denenir, sonrahataolur. ARCO yedeği burada kullanılmaz (saat başına ~324 MB). Pencere deposu (ML_DEPO_KLASORU, varsayılanml_ozellik_deposu/): dilim silinmeden önce her PIREP'in çevresindeki pencere (±1°, ±1 saat, 150-350 hPa arası 7 seviye, u/v/t + bağıl nem) gün bölümlemeli NetCDF'e yazılır; yoluml_ornekleri.pencere_dosyasi'nda tutulur. İstek sayısı değişmez, yalnızca istek boyutu büyür. Mevcut özellikler kalibrasyon tutarlılığı için yine 300/250/200 hPa'dan hesaplanır; yeni bir özellik CDS'e gitmeden depodan hesaplanabilir (bkz. ADR 0002):turbulans-ml-depo --ozet # dosya, boyut, pencereli/penceresiz örnek turbulans-ml-depo --dogrula 200 # depodan yeniden hesapla, DB ile kıyasla turbulans-ml-depo --eksikleri-kuyruga-al # depo öncesi eşleşmiş örnekleri yeniden indir
-
Eğitim (champion/challenger,
ml/ml_otomatik_egitim.py): en azML_MIN_ORNEKörnek veML_MIN_GUNfarklı gün varsa, dondurulmuş altın test günleri (ml/altin_test_gunleri.json; yoksa en sonML_HOLDOUT_ORANIgün) ayrılır. Bu günler hiçbir sürümün eğitimine girmez; yayına giren model de yalnızca eğitim günleriyle eğitilir ve sürüm kaydınaegitim_gunleriyazılır. Aday, eğitim günlerinde gün bazlı gruplu CV ROC-AUC'siyle seçilir; Lojistik Regresyon ile farkı en iyi modelin kat standart hatasından küçükse Lojistik Regresyon seçilir (1-SE kuralı). Gradient Boosting sınıf dengeli ağırlıkla eğitilir. Özellikler:ti1_indeksi,richardson_sayisi,ruzgar_hizi_ms,basinc_hpave tahmin anında aynı küpten hesaplanandusey_ruzgar_kaymasi,yatay_deformasyon,yatay_diverjans,ti2_indeksi. Kapı iki aşamalıdır: (1) holdout'ta ROC-AUC tek başına TI1'i en azML_TI1_AUC_USTUNLUGUgeçmeli ve gün bazlı eşleştirilmiş bootstrap ile farkın %95 güven aralığının alt sınırı 0'ın üstünde olmalı (test günleri her gece yeni adaylarla yeniden kullanıldığı için nokta farkı şansla geçilebilirdi); (2) aktif model varsa ona karşı da aynı kural (ML_SAMPIYON_AUC_USTUNLUGU, 0,02). Altın günleri eğitiminde görmüş aktif model karşılaştırmada yok sayılır. Aksi halde yalnızca versiyon olarak (aktiflestirildi: false, karar gerekçesiyle) saklanır ve elle/aktiflestirile açılabilir. Ek özelliklerden önce kaydedilen MADIS EDR örnekleri içinturbulans-madis ozellik-tamamlaeksik özellikleri pencere deposundan hesaplar (kayıtlı değerler değişmez).
CDS kotası kod seviyesinde: her gerçek CDS isteğinden önce
hiz_siniri_sayaclari üzerinden süreçler arası günlük sayaç artırılır;
CDS_GUNLUK_MAKS_ISTEK (150, UTC gece yarısı sıfırlanır) aşılırsa istek
gönderilmez. ML gecesi ayrıca ML_GECE_MAKS_CDS_ISTEK (30) ile sınırlıdır;
API 150'nin üstünü reddeder (422), istenen değer bu sınıra indirilir.
Veritabanına ulaşılamazsa sayım süreç içinde tutulur.
Günlük veri bütçesi: istek sayısı ban korumasıdır, veri miktarını
sınırlamaz (CDS dosyası 1-20 MB). Gece işinin CDS ve MADIS indirmeleri
gerçek bayt olarak aynı tabloda UTC günü başına toplanır
(depo/veri_butcesi.py); GUNLUK_VERI_BUTCESI_MB (500, 0 = kapalı)
dolacaksa yeni grup/gün indirilmez (durdurma: gunluk_veri_butcesi).
Bugünkü kullanım GET /api/v1/ml/durum → veri_bugun_mb. Elle başlatılan
uçuş analizleri bütçeye tabi değildir.
Tetikleme: POST /api/v1/ml/gece-isi (yönetici; gövde isteğe bağlı:
iem_guncelle, maks_cds_istek, ardindan_egitim) ml_veri görevini
kuyruğa alır; bu görev bitince ml_egitim görevini zincirler. Aynı anda
ikinci bir ML işi kuyruğa alınmaz (409); iki işçi aynı işi alsa bile
dağıtık kilit yalnızca birini çalıştırır. Durum: GET /api/v1/ml/durum
(örnek sayıları, eşleşmiş gün sayısı ve 60 gün barajı, bugünkü CDS kullanımı,
IEM imleci, aktif model sürümü, son ML görevleri).
Aktivasyon kapısı: aday modelin olasılıkları gün bazında gruplu çapraz
doğrulamayla sigmoid (Platt) yöntemiyle kalibre edilir. Aday, altın test
günlerinde (1) TI1'i ve (2) varsa aktif modeli eşleştirilmiş ROC-AUC farkıyla
geçmelidir: nokta farkı ≥ 0,02 ve gün bazlı bootstrap %95 GA alt sınırı > 0
(ADR 0004); aksi halde
yalnızca sürüm olarak saklanır. Test raporu ROC-AUC, POD, POFD, Peirce, Brier
ve Brier becerisini içerir (ml/degerlendirme.py). POD/POFD/Peirce her iki skor
için de eğitim günlerinde Peirce'ı maksimize eden eşikle (esikler), Brier
referansı tek değişkenli lojistik "kalibre TI1" ile hesaplanır. Her metrik gün
bazlı blok bootstrap %95 güven aralığıyla raporlanır (deney protokolü).
Veri dondurma (18 Ekim 2026): turbulans-ml --dondurma-raporu docs/sonuclar/2026-10-18
o günkü ml_ornekleri ile bir kez eğitip değerlendirir ve sürüm kaydını klasöre
yazar. Sonuç ne çıkarsa raporlanır; "model TI1'i geçemedi" de geçerli bir bulgudur.
Belirsizlik ("emin değilim" diyebilen çıktı): eğitimde gün gruplu kat dışı
olasılıklardan konformal bir eşik hesaplanıp modelle saklanır (ml/belirsizlik.py).
POST /api/v1/turbulans/tahmin olasılığın yanında ml_risk_durumu döner:
yuksek_risk, dusuk_risk ya da veri iki sınıfı bu güven düzeyinde ayıramıyorsa
belirsiz. Hedef kapsama 1 - ML_KONFORMAL_ALFA (%90); altın test günlerinde
ölçülen kapsama ve belirsiz oranı sürüm kaydında ve 3B haritanın model panelinde
görünür. Kapsama yalnızca ERA5 girdisinde doğrulanmıştır: yanıt veri_kaynagi
içerir, canlı GFS'de ml_konformal_hedef_kapsama null ve ml_konformal_notu
"doğrulanmadı" döner. ml_riski_var_mi eşiği ML_KARAR_ESIGI (risk iştahı)
verilmişse odur; verilmezse modelin eğitim günlerindeki Peirce eşiği, o da yoksa 0,5.
Doğrulama, EDR kalibrasyonu ve sürüm yönetimi (CLI):
turbulans-ml-degerlendirme # aktif model + tek başına TI1 referansı, güvenilirlik tablosu
turbulans-ml-degerlendirme --kesme 2026-10-18 --cikti docs/sonuclar/2026-10-18 # sonuç paketi (Madde 8)
turbulans-performans rota # rota kararı ve A* süresi, sabit senaryolar
turbulans-edr-kalibrasyon # TI1 görsel ölçeği katsayısı (EDR değildir), gün bazlı bootstrap GA
turbulans-ml --listele # kayıtlı model sürümleri (aktif edildi / saklandı + gerekçe)
turbulans-ml --geri-al VERSIYON_ID # tek komutla geri alma
turbulans-ml --muhurle # sha256 kaydı olmayan modellere özet ekler (bütünlük doğrulaması)
turbulans-ml --kayma # aktif modelin eğitim verisine göre özellik kayması (PSI/KS)
turbulans-ml --altin-gunleri-dondur # altın test günlerini bir kez seçer (dosya varsa yazmaz)
turbulans-ml --dondurma-raporu KLASOR # bir kez eğit + değerlendir, sonucu KLASOR'e yazturbulans-edr-kalibrasyon, EDR_OLCEKLENDIRME_KATSAYISI'nı ml_ornekleri'ndeki
doğru irtifalı PIREP'lerle yeniden uydurur: en son günler test için ayrılır,
güven aralığı gün bazlı bootstrap ile hesaplanır (aynı günün raporları
bağımsız değildir), eski (0.23) ve yeni katsayının test hatası karşılaştırılır.
Eski değer EDR_OLCEKLENDIRME_KATSAYISI_ESKI olarak saklanır. Bu "TI1 görsel
ölçeği" EDR değildir; PIREP şiddet sınıfının beklenen değerine uyan görsel bir
ölçektir. Bayrağı TI1_GORSEL_OLCEK_PIREP_SINIFINA_UYDURULDU'dur (eski adı
EDR_OLCEKLENDIRME_KATSAYISI_KALIBRE_EDILDI).
Ek özellikler: eşleştirme her nokta için düşey rüzgar kayması, yatay
deformasyon, yatay diverjans ve Ellrod-Knox TI2'yi (VWS × (DEF + yakınsama))
da üretir; bunlar ml_ornekleri'ne kaydedilir ve modelde kullanılır (bkz.
yukarıdaki 4. adım). Dağ dalgası ve konveksiyon özellikleri için ERA5'ten ek alanlar
gerekir: yüzey jeopotansiyeli (geopotential, tek seviye; arazi) ve CAPE
(convective_available_potential_energy, tek seviye).
n8n kurulumu (isteğe bağlı): Bu projenin kendi kurulumunda n8n
kullanılmıyor; gece işini API'nin zamanlayıcısı (ML_GECE_ISI_SAATI)
tetikliyor. n8n tercih edilirse zamanlayıcıyı kapatın (ML_GECE_ISI_SAATI=)
ve otomasyon/n8n_gece_isi.json'ı n8n'de Import from file
ile içe aktar. Bir Header Auth kimlik bilgisi oluştur (Name: X-API-Key,
Value: yönetici anahtarı) ve "Gece işini tetikle" düğümüne bağla. API adresi
TURBULANS_API_URL ortam değişkeninden okunur (yoksa http://localhost:8000;
n8n'de N8N_BLOCK_ENV_ACCESS_IN_NODE=false gerekir). Akış her gece 02:00
UTC'de tetikler; ağ hatasında 3 kez yeniden dener; 202/409 dışındaki yanıtta
"Stop and Error" ile çalıştırmayı hatalı bitirir — bildirim için n8n'de bir
Error Workflow tanımla.
Hava küpünde ERA5 bağıl nemi (r) varsa her nokta için kalıcı iz bulutu
duyarlılığı hesaplanır (fizik/iz_bulutu.py): T ≤ T_LC(p) ve buza göre bağıl
nem ≥ %100. T_LC, basınca bağlı Schmidt–Appleman eşik sıcaklığıdır (η = 0,4,
SAC_ITKI_VERIMI; sabitler ve Murphy–Koop doyma basınçları Sun ve Roosenbrand
2023, JOAS 1). RHi = %100 için 200/250/300 hPa'da sırasıyla −49,1 / −46,9 /
−45,0 °C'dir; eski sabit −40 °C ölçütü IZ_BULUTU_OLCUTU=sabit ile seçilebilir.
ERA5 bağıl nemi −23 °C'nin altında buza göre verilir (ECMWF ERA5 belgeleri), bu
yüzden dönüşüm gerekmez.
- Uçuşa özel ERA5 dilimi nemi de indirir (
ERA5_UCUS_EK_DEGISKENLER; istek sayısı aynı, dosya ~%30 büyük). Eşleşmeyebuz_bagil_nem_yuzdeveiz_bulutu_duyarlisütunları, rota yanıtına ve seçeneklereiz_bulutu_nokta_sayisieklenir. - Nem içermeyen küplerde (yerel arşiv küpleri, GFS) değer
null'dır; GFS'nin nem tanımı doğrulanmadığı için orada hesaplanmaz. - Yalnızca göstergedir, rota maliyetine girmez. ERA5 buzda aşırı doymayı az gösterir (bkz. ACP 25, 157, 2025); sonuç gözlenmiş iz bulutu değildir.
- Önerilen rotada duyarlı nokta varsa yanıtın
iz_bulutu_seviye_bilgisialanı aynı izin ±2000 ft'teki duyarlı nokta sayısını verir (Sun vd., 2024: irtifa sapmasıyla önleme). Bilgi amaçlıdır; yakıt, yarım daire kuralı ve ATC değerlendirilmez.
Türbülansın en doğrudan sensörü onu yaşayan uçaktır. Seyir fazındaki bir uçağın atanmış seviyesinden ani irtifa sapması (ADS-B barometrik irtifa + düşey hız) "sanal PIREP" olarak kaydedilir; aynı bölgede birden çok uçağın işareti kümelenir. Yöntem, eşiklerin dayanağı ve bedeli: docs/adr/0011.
- Girdi: işçideki her uçuş/rota analizinin izi (OpenSky'a ek sorgu yok) ve
havayolu beslemesi için
POST /api/v1/sanal-pirep/iz. - Uyarı: en az
SANAL_PIREP_BILDIRIM_MIN_UCAK(2) farklı uçağın doğruladığı olaylar/ws/uyarilar'atip: "sanal_pirep"olarak gider; gecikmebildirim_zamani - bitisolarak her olayda saklanır. - Sınır: sapma ham büyüklüktür, EDR ya da şiddet sınıfı değildir; eşikler kalibre edilmemiştir. Sinyal ML eğitim etiketi olarak kullanılmaz.
- ERA5 uyum etiketi: işçi izinde ERA5 TI1 varsa bildirim
era5_uyumu(uyumlu/uyumsuz/bilinmiyor) veera5_ti1taşır. Etiket olayı elemez ve kalıcı kayıtta yoktur; ATC/TCAS kaynaklı sapmaları ayırt etmeye yardım eder, başarımı ölçülmedi. - Doğrulama (POD/POFD):
turbulans-sanal-pirep dogrula --pozitif 50 --negatif 50ml_ornekleri PIREP'lerini çevrelerindeki ADS-B izleriyle karşılaştırır. Varsayılan yalnızca önbelleği okur;--maks-yeni-sorgu N(en fazla 20) PIREP başına tek OpenSky sorgusu atar ve sonucuopensky_onbellek/pirep_cevresi/altına yazar. - Tek bir izi denemek:
turbulans-sanal-pirep iz opensky_onbellek/UCUS_TARIH.parquet.
turbulans-anomali-tabani aynı önbellek izlerinde Isolation Forest ve LOF'u
kural tabanlı dedektörle eşit alarm bütçesiyle kıyaslar (POD/POFD/Peirce, Wilson
aralığı; OpenSky'a sorgu yok). İlk ölçüm (16 PIREP): kural POD 1/8, POFD 0/8;
IF 2/8–3/8; LOF 5/8–5/8. Denetimsiz yöntemler ayırt edici çıkmadı; ön bulgu,
ayrıntı ADR 0011.
POST /api/v1/sanal-pirep/canli-oturum (yönetici) ya da turbulans-canli-adsb
bir bölgeyi (varsayılan merkez 39°K 35°D, 250 NM) süreli olarak (varsayılan
15 dk, en fazla 60) 10 sn'de bir sorgular; oturum sonunda her uçağın izi sanal
PIREP hattından geçer. Geçmiş analiz için değil, canlı gözlem içindir.
- Kaynak zinciri: adsb.fi açık veri (saniyede 1 istek, yalnızca kişisel/ticari olmayan kullanım, adsb.fi'ye atıf ve bağlantı zorunlu), sonra ADSB.lol (ODbL 1.0). airplanes.live genel API'si Nisan 2026'da kapandığı için yok.
- Koruma: varsayılan kapalı (
CANLI_ADSB_ETKIN), istekler arası en az 5 sn, günde en fazla 1000 istek, aynı anda tek oturum, 429'da sağlayıcı 5 dk atlanır, tanıtıcıUser-Agent. - Oturum özeti kullanılan kaynağın atıf metnini döner; sunum ve raporda kullanılırsa atıf verilmelidir.
Pilot raporuna (PIREP) ek olarak, uçakların kendi ölçtüğü türbülans (EDR) NOAA MADIS'in herkese açık ACARS arşivinden alınır ve ERA5 pencere deposuyla eşleştirilir (CDS'e ek istek yok). Ayrıntı ve kısıtlar: ADR 0012.
- Gece işi, penceresi olan PIREP günlerinden gece başına en fazla birini indirir (24 saatlik dosya, aralarında 5 sn; günde en fazla 48 dosya).
turbulans-madis gun 2019-06-12tek günü işler,turbulans-madis ozetEDR sınıflarını ve PIREP-EDR karşılaştırmasını verir.turbulans-madis degerlendirTI1'i ve (doğru veriyle eğitilmiş) aktif modeli ölçülen EDR'ye karşı değerlendirir: hedef "hafif ve üstü", ROC-AUC, POD/POFD, gün bazlı bootstrap GA (en az 5 gün; daha azsaon_sonuc).- Şiddet sınıfları ICAO tepe EDR eşikleriyle: hafif 0,1, orta 0,4, şiddetli 0,7.
- Public veri QC'siz ön veridir ('Z'); yeniden dağıtılmaz, depoya konmaz.
Bu depodaki örnek veri kümesi (Türkiye/Doğu Akdeniz, Ocak 2019) için gerçek
PIREP/AMDAR gözlem verisi yok (bkz. kalibrasyon.py; ML sınıflandırıcısı
için ABD hava sahasından indirilen gerçek IEM PIREP verisi ayrı bir konu --
bkz. Makine öğrenmesi tabanlı türbülans sınıflandırıcısı)
-- ama SIGMET'ler (Significant Meteorological Information) de gerçek,
operasyonel "burada tehlikeli hava durumu var" uyarılarıdır ve halka açık,
ücretsiz bir arşivden çekilebilirler. sigmet_dogrulama.py, hesaplanan TI1
"orta-şiddetli" noktalarını, Iowa Environmental Mesonet'in (IEM) 2005'ten
bugüne arşivlediği ABD Aviation Weather Center (AWC) SIGMET kayıtlarıyla
karşılaştırır -- gerçek zaman/konum eşleşmesi (poligon içi + geçerlilik
penceresi) kontrol edilir, sadece TÜRBÜLANSLA ilgili SIGMET'ler (metninde
"TURB" geçenler) dikkate alınır.
python -m turbulans_radar.dogrulama.sigmet_dogrulama THY1234 2019-01-01
# veya API üzerinden:
curl http://localhost:8000/api/v1/ucuslar/THY1234/2019-01-01/sigmet-dogrulama \
-H "X-API-Key: $API_ANAHTARI"ÖNEMLİ SINIRLAMA: Bu arşiv SADECE ABD'nin meteorolojik sorumluluk
sahasını (CONUS + New York/Oakland/Anchorage Oceanic FIR'ları gibi ABD
kontrolündeki okyanus bölgeleri) kapsar. Bu depodaki örnek veri kümesi
(Türkiye/Doğu Akdeniz, Ocak 2019) için GERÇEKTEN eşleşen bir SIGMET
bulunmaz -- bu bir hata değil, beklenen ve dürüst bir sonuçtur
(sigmetle_ortusen_nokta_sayisi=0 döner). Özellik, ABD hava sahasında
geçen herhangi bir uçuş/tarih için gerçek anlamda doğrulama sağlar (bkz.
modülün kendi docstring'indeki örnek: Anchorage FIR, 2019-01-15, gerçek bir
"OCNL SEV TURB" SIGMET'i ile doğrulandı).
GET /api/v1/sigmet/{id}/iwxxm saklanan SIGMET'i ICAO/WMO IWXXM 2025-2 XML'ine
yeniden kodlar (veri/iwxxm.py; yapı WMO'nun resmi örneği wmo-im/iwxxm
sigmet-A6-1a-TS.xml'i, olgu kodları WMO 49-2 SigWxPhenomena listesini izler).
- Çıktı resmi XSD'ye (schemas.wmo.int/iwxxm/2025-2) göre doğrulandı (xmlschema, 2 Ekim 2026; tam, eksik alanlı ve gerçek AWC örnek kaydıyla). Schematron kuralları ayrıca çalıştırılmadı.
- Mesaj
permissibleUsage="NON-OPERATIONAL"(TEST): AWC verisinin yeniden kodlamasıdır, yetkili MWO yayını değildir. Kaynakta MWO kodu olmadığı için FIR kodu kullanılır; eksik seri numarası ve gözlem/tahmin ayrımı varsayımlarıpermissibleUsageSupplementary'de yazılıdır. - WMO koduna kesin eşlenemeyen olgular (ABD'ye özgü CONVECTIVE, niteleyicisi bilinmeyen TS) 422 döner.
Ölçülmüş gecikme, verim ve görev hızı değerleri (hedeflerle birlikte):
docs/PERFORMANS_RAPORU.md. Ölçüm tekrarlanabilir:
turbulans-performans hepsi (bölümler: analiz, api, gorev, gece).
- Prometheus (
GET /metrics): yönetici anahtarı ister (X-API-Keyya daAuthorization: Bearer <anahtar>, Prometheusscrape_config->authorization). Zaman serileri:turbulans_http_istekleri_totalveturbulans_http_istek_suresi_saniye(etiket: route şablonu, ham yol değil),turbulans_rota_hesabi_suresi_saniye(A* dağılımı),turbulans_hiz_siniri_reddi_total,turbulans_agir_hesap_reddi_total,turbulans_gorev_kuyrugu{durum},turbulans_gorev_kuyrugu_en_eski_bekleme_saniye,turbulans_sigmet_yas_saniye,turbulans_ws_baglanti_sayisi. Örnek alarmlar: SIGMET yaşı > 1800 sn, A* p95 > 5 sn, en eski bekleme > 120 sn. - Hazır izleme yığını (P1-3):
docker compose --profile izleme up -d prometheus->http://127.0.0.1:9090. Ayarizleme/prometheus.yml, alarmlarizleme/alarmlar.yml(API erişilemiyor, SIGMET bayat, kuyruk birikiyor, rota p95 > 5 sn, 429 artışı). Bildirim kanalı yok; alarmlar "Alerts" sekmesinde görünür. Prometheus/metrics'i kendi yönetici anahtarıyla okur:.env'deAPI_ANAHTARLARI=prometheus:yonetici:<anahtar>ve aynı anahtarı içeren depo dışı dosyaPROMETHEUS_ANAHTAR_DOSYASI(Docker secret). - Yapılandırılmış log:
LOG_BICIMI=jsonile satır başına bir JSON nesnesi (zamanUTC,seviye,kaynak,mesaj,hata) -- Loki/ELK alanları ayrıştırmadan sorgular. GET /saglik?derin=true(anahtarsız, monitoring için): PostgreSQL erişilemezse 503. Erişilebilirse HTTP 200 ve bağımlılık başına durum:sigmet(son BAŞARILI çekimin yaşıSIGMET_BAYATLIK_DAKIKA'yı aşarsabayat, bir AWC kaynağı hata veriyorsahata),canli_gfs(son indirme başarılı mı),gorev_kuyrugu(en eski bekleyen görev 2 dakikadan eskiysebirikiyor-- işçi yok ya da yetişemiyor),kisitli_sahalar,kup_onbellegi,statik_dosyalar. Operasyonel bir sorun genel durumubozulmusyapar; yapılandırma eksikleri (eksikweb kütüphanesi,ornek_veri,veri_yok)uyarilar'da listelenir. Dış servislerin ham hata metinleri anahtarsız uçta gösterilmez;GET /api/v1/sistem/durum(anahtarlı) aynı raporu hata ayrıntılarıyla verir.- Canlı veri alınamadığında rota yanıtı artık "kapsam dışı" değil
ruzgar_verisi_kaynagi: canli_veri_alinamadive açıklamada UYARI döner; her GFS indirmesinin sonucuveri_kaynagi_durumlari'na yazılır. - Kütüphaneler yerelden:
web/harita3d.htmlveweb/ucus_simulasyonu.htmlMapLibre/CesiumJS'i önce API'nin kendisinden (web/vendor/, bkz.turbulans-statik) yükler, yoksa CDN'e düşer. Paketler npm'den koda sabitlenmiş sha512 bütünlük değeriyle doğrulanarak indirilir (değiştirilmiş paket kurulmaz); kesintili bağlantıda indirme kaldığı yerden devam eder. - Çevrimdışı altlık harita: Cesium sahnesinin altlığı paketle gelen
NaturalEarthII dokusu, MapLibre haritasınınki sunucudan gelen sade ülke
sınırları (
web/veri/ulke_sinirlari.geojson, Natural Earth, kamu malı). Esri sokak haritası üstte ek katmandır: bağlantı yoksa karoları gelmez ama harita boş kalmaz.
İsteğe bağlıdır; bu projenin kendi kurulumunda n8n çalışmıyor. Docker
yığını iki düzenli işi kendisi yürütür: canlı SIGMET yenilemesi
(SIGMET_OTOMATIK_GUNCELLEME_DAKIKA, 15 dk) ve ML gece işi
(ML_GECE_ISI_SAATI, o saatten sonraki ilk açılışta). Aşağıdaki tablo, bu
işleri ya da diğerlerini dış bir zamanlayıcıdan (n8n, cron) tetiklemek
isteyenler içindir; aynı iş için iki zamanlayıcıyı birlikte açmayın.
Otomasyon tarafı projenin Python iç yapısını bilmez; her iş, n8n'de bir
Schedule Trigger + HTTP Request node çiftidir. Tüm isteklere
X-API-Key başlığı eklenir (anahtarı n8n'de bir Credential ya da ortam
değişkeni olarak tut, iş akışına düz metin yazma):
| İş | Sıklık | HTTP Request | Not |
|---|---|---|---|
| Canlı SIGMET yenileme | 10-15 dk | POST /api/v1/sigmet/guncelle |
A*'ın sert kısıtı bu tabloyu kullanır; son çekim 30 dk'dan eskiyse canlı rota yanıtları bayat_mi uyarısı taşır. Alternatif: SIGMET_OTOMATIK_GUNCELLEME_DAKIKA ile API'nin kendi zamanlayıcısı (Docker'da varsayılan 15 dk) -- ikisini aynı anda açmaya gerek yok. |
| Canlı GFS önceden ısıtma (isteğe bağlı) | 6 saatte bir, döngülerden ~4 sa sonra | POST /api/v1/veri/canli/hazirla (gövde: bölge kutusu, saat_sayisi) |
Kuyruğa girer (202); küp özeti görevin ozet alanında. Sık kullanılan bölgenin ilk rota isteği indirme süresini beklemez. |
| Toplu uçuş analizi | ihtiyaca göre | POST /api/v1/analiz/toplu |
bildirim_webhook_url ile bitince n8n Webhook node'una bildirim ya da GET /api/v1/analiz/durum/{gorev_id} yoklaması. |
| Toplu backtest (isteğe bağlı) | günlük | POST /api/v1/backtest/toplu?limit=50 |
Yeni analiz edilen uçuşları A* rotasıyla karşılaştırır; özet GET /api/v1/backtest. |
| ML gece işi | her gece (örn. 02:00 UTC) | POST /api/v1/ml/gece-isi |
Yeni IEM PIREP'leri + CDS ile ERA5 eşleştirmesi (gecelik/günlük CDS sınırlı) + champion/challenger eğitim. 409 dönerse önceki gece işi sürüyordur; sonuç GET /api/v1/analiz/durum/{gorev_id} (eğitim görevinin kimliği ozet[0].egitim_gorev_id). Alternatif: ML_GECE_ISI_SAATI (UTC, SS:DD) ile API'nin kendi zamanlayıcısı (Docker'da varsayılan 23:07 UTC = 02:07 TSİ); API o saatte kapalıysa aynı gün açılınca bir kez telafi eder. İkisini aynı anda açmayın. |
Uzun işlerde n8n asla beklemez: istek 202 + gorev_id döner. Sonuç için
ya bildirim_webhook_url (n8n Webhook node'u) verilir ya da GET /api/v1/analiz/durum/{gorev_id} durum kuyrukta/calisiyor olduğu sürece
yoklanır. API sadece .env'den beslenen, uvicorn/Docker ile başlatılan
bağımsız bir HTTP servisidir.
Proje kökündeki .mcp.json, mcp_postgres_sunucusu.py'yi Claude Code'a
tanıtır (ilk kullanımda onay istenir). Sunucu salt okunur -- sadece
tablolari_listele, ucuslar_listesi, ucus_detayi ve
salt_okunur_sorgu_calistir (sadece tek bir SELECT, yazma ifadeleri
reddedilir) araçlarını sunar. Bağlantı bilgileri .mcp.json'da DEĞİL,
.env'de tutulur; MCP_POSTGRES_HOST/PORT/USER/PASSWORD verilirse
POSTGRES_* yerine onlar kullanılır. MCP_POSTGRES_USER/PASSWORD boşsa ya da
kullanıcı postgres/uygulama kullanıcısıysa sunucu başlamaz; bağlanan rol süper
kullanıcı, rol ya da DB oluşturabiliyorsa ilk sorguda reddeder. pg_*, lo_*,
dblink, set_config gibi fonksiyon çağrıları da filtrelenir.
Claude Code Windows'ta çalışıp veritabanı Docker'da (WSL) ise: Windows'ta
yerel bir PostgreSQL 5432'yi tutuyorsa localhost:5432 o sunucuya gider ve
MCP eski/başka bir veritabanını okur. Docker veritabanı bu yüzden
127.0.0.1:5433'e de açılır. Kelime filtresinin yanında veritabanı düzeyinde
de yazmayı engellemek için salt okunur bir rol kullanın (bir kez):
docker compose exec db psql -U postgres -d Turbulence-db \
-c "CREATE ROLE turbulans_okuyucu LOGIN PASSWORD '<güçlü şifre>'" \
-c "GRANT pg_read_all_data TO turbulans_okuyucu" \
-c "ALTER ROLE turbulans_okuyucu SET default_transaction_read_only = on".env: MCP_POSTGRES_PORT=5433, MCP_POSTGRES_USER=turbulans_okuyucu,
MCP_POSTGRES_PASSWORD=<aynı şifre>. Değişiklikten sonra Claude Code'u
yeniden başlatın.
alembic upgrade head # şemayı kur/güncelle
alembic current # hangi migration'da olduğunu gösterir
alembic revision --autogenerate -m "kisa aciklama" # yeni migrationBağlantı bilgisi alembic.ini'ye yazılmaz; migrations/env.py, tıpkı
veritabani.py gibi, .env'den okur. Docker'da şema migrate servisinde güncellenir; ondan
hemen önce migrate_yedegi db_yedekleri/migration_oncesi/'ne pg_restore -l ile doğrulanmış
bir dump yazar (en yeni 5'i tutulur, MIGRATION_YEDEK_SAKLA). Yedek alınamazsa migration ve API
başlamaz. Geri dönüş: README "Veritabanı yedeği"ndeki pg_restore komutu bu dosyayla.
Docker yığınındaki yedek servisi (otomasyon/db_yedekle.sh) o UTC günü
yedek yoksa iki dosya üretir (depoya konmaz):
db_yedekleri/turbulans_YYYYAAGG.dump:pg_dump -Fc;pg_restore -lile okunamazsa yerine konmaz.db_yedekleri/dosyalar_YYYYAAGG.tar.gz: veritabanında olmayan, yeniden indirmesi pahalı dosyalar (ml_ozellik_deposu/,madis_edr/,opensky_onbellek/, model sürümleri volume'u);tar -tzile okunamazsa yerine konmaz.- Disk dışı kopya (isteğe bağlı):
docker-compose.override.yml(depoya girmez) yedek servisine/dis_yedekbağlarsa, yeni yedekler oraya da kopyalanır ve aynı saklama süresi uygulanır. Örnek: bir OneDrive klasörü (- /mnt/c/Users/<kullanici>/OneDrive/TurbulansRadar_Yedekleri:/dis_yedek); OneDrive'a giriş yapılmamışsa klasör buluta eşitlenmez. - Disk dışı kopyanın şifrelenmesi:
.env'deYEDEK_PAROLA_DOSYASI(depo dışında, tek satırlık parola dosyası; WSL yolu) verilirse kopyalar gpg AES256 ile*.gpgolarak yazılır ve aynı yedeğin şifresiz kopyası silinir. Yereldb_yedekleri/hızlı geri yükleme için şifresiz kalır; diski Windows Cihaz Şifrelemesi/BitLocker korur. Parolayı bir parola yöneticisine de kaydedin -- kaybolursa şifreli kopyalar açılamaz. Açmak:gpg --batch --pinentry-mode loopback --passphrase-file <parola> -o turbulans_YYYYAAGG.dump -d turbulans_YYYYAAGG.dump.gpg.
Başarısız deneme (ör. açılışta veritabanı henüz hazır değil)
YEDEK_YENIDEN_DENEME_SANIYE (60) sonra tekrarlanır; eskiden bir saat
bekleniyordu ve kısa açık kalan günlerde yedek hiç alınmıyordu. Başarıdan
sonra saatte bir bakılır; her türden en yeni DB_YEDEK_SAKLA_GUN (7) dosya
tutulur. Durum: docker compose logs yedek. Bilgisayar arızasına karşı
disk dışı kopyayı (yukarıda) açık tutun.
Geri yükleme (önce API ve işçiyi durdurun; mevcut tablolar silinip yedekle değiştirilir):
docker compose stop api worker
docker compose exec -T db sh -c 'pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --clean --if-exists --no-owner' < db_yedekleri/turbulans_20261002.dump
sh otomasyon/uygulama_rolu_olustur.sh # geri yüklenen tablolar postgres'e ait olur; sahipliği uygulama rolüne geri ver
docker compose start api workerGeri yükleme tatbikatı (haftalık). yedek servisi son 7 günde rapor yoksa en yeni
dump'ı kendi içinde geçici bir PostgreSQL sunucusuna (yalnız unix soketi) yükler; tablo
listesi, alembic sürümü ve satır sayıları canlıyla karşılaştırılır. Rapor
db_yedekleri/tatbikat/tatbikat_YYYYAAGG.txt; eksik tablo, farklı alembic sürümü, boş
sayım ya da canlının yarısından az satır "KALDI" sayılır ve logda
GERI YUKLEME TATBIKATI BASARISIZ yazar. Elle:
docker compose exec yedek sh /geri_yukleme_tatbikati.sh [/yedekler/turbulans_YYYYAAGG.dump].
Canlı veritabanına yalnız okuma sorgusu gider. İlk tatbikat (18 Ekim 2026): 10 MB dump,
3 sn, 16 tablonun hepsi canlıyla aynı.
Kalıcı yedekler. db_yedekleri/kalici/ saklama süresiyle silinmez ve disk dışı
kopyaya bir kez (şifreliyse .gpg) yazılır. Veri dondurma günü yedeği
(turbulans_20261018_dondurma.dump, dosyalar_20261018_dondurma.tar.gz) buradadır; nihai
sonuç paketi bu yedekle yeniden üretilir.
Hedefler (RPO / RTO). Bu tek makinelik geliştirme yığını içindir, üretim SLA'sı değildir.
- RPO (kabul edilen en büyük veri kaybı): 24 saat. Yedek her UTC gününün ilk açılışında alınır; bilgisayar kapalı kalan günlerde yeni veri de girmez, kayıp süresi uzamaz. Gece işinin bir günlük eşleşmesi kaybolursa ertesi gece yeniden indirilebilir (CDS bütçesi).
- RTO (aynı makinede geri dönüş): 15 dakika. Ölçülen geri yükleme 3 sn; süreyi servisleri durdurma/başlatma ve uygulama rolü betiği belirler.
- RTO (disk kaybı, yeni makine): 1 iş günü. Docker/WSL kurulumu, depo klonu, OneDrive'daki
.gpgkopyanın parola yöneticisindeki parolayla çözülmesi ve geri yükleme. Bu senaryo uçtan uca denenmedi; 8 Ekim'de yalnız.gpgkopyanın çözülüp yerel dump ile aynı sha256'yı verdiği doğrulandı.
API, işçi ve demo postgres süper kullanıcısıyla değil, yalnızca kendi
veritabanının ve tablolarının sahibi olan turbulans_uygulama rolüyle
bağlanır: migration çalıştırabilir, kendi tablolarına yazabilir; başka
veritabanlarına, rollere ve sunucu dosyalarına (COPY ... PROGRAM,
pg_read_file) erişemez. Süper kullanıcı şifresi yalnızca db ve yedek
servislerinde kalır; API/işçi konteynerlerinde MCP okuyucu şifresi de boştur.
# .env: UYGULAMA_POSTGRES_USER=turbulans_uygulama, UYGULAMA_POSTGRES_PASSWORD=<güçlü şifre>
sh otomasyon/uygulama_rolu_olustur.sh "Turbulence-db-test" # önce test veritabanında
sh otomasyon/uygulama_rolu_olustur.sh # sonra asıl veritabanı
docker compose up -d api workerBetik tekrar çalıştırılabilir (şifre değişikliği için de). UYGULAMA_* boşsa
servisler eski davranışla POSTGRES_USER'la bağlanır (CI, demo). Testler
<POSTGRES_DB>-test veritabanını oluşturabilmek için .env'deki
POSTGRES_USER ile çalışır.
pip install -e ".[dev]"
pytest tests/test_eslestirme.py gerçek .nc dosyasını, test_veritabani.py/
test_api_servisi.py gerçek bir PostgreSQL bağlantısını bulamazsa
otomatik atlanır (skip) -- CI'da Postgres bir servis konteyneriyle
sağlanır, .nc dosyası (büyük olduğu için) sağlanmaz.
Testler katmanlara ayrılır; tests/conftest.py her testi kullandığı
fixture'lara göre otomatik işaretler (bkz. pytest.ini markers):
| Katman | Gereksinim | Çalıştırma |
|---|---|---|
birim |
Hiçbiri (sahte istemci/veri, geçici klasör) | pytest -m birim (saniyeler) |
veritabani |
Gerçek PostgreSQL | pytest -m veritabani |
gercek_veri |
Gerçek ERA5 küpü, eğitilmiş model, PIREP verisi | pytest -m gercek_veri |
tarayici |
Playwright + Chromium (aşağıya bakın) | pytest -m tarayici |
ag |
Gerçek dış servis (Copernicus CDS; kimlik: CDSAPI_RC / ~/.cdsapirc) |
pytest -m ag |
ag testleri kota harcadığı için varsayılan çalıştırmada hariçtir
(pytest.ini: -m "not ag"); -m verilince bu varsayılan ezilir.
Katmanlar birleştirilebilir, örn. pytest -m "birim or veritabani".
Yerelde testler geliştirme veritabanına değil, otomatik oluşturulan ayrı bir
<POSTGRES_DB>-test veritabanına bağlanır (adı POSTGRES_TEST_DB ile
değiştirilebilir; CI'da CI tanımlı olduğundan kendi veritabanı kullanılır).
Böylece çalışan Docker işçisi testlerin görevlerini almaz, geliştirme verisi
kirlenmez.
Windows'ta Smart App Control yerelde postgres.exe ve pandas'ın derlenmiş
modüllerini engelleyebilir; bu durumda testleri WSL2 içinde çalıştırın
(Postgres için docker compose up -d db).
test_web_harita3d.py/test_web_ucus_simulasyonu.py, gerçek bir tarayıcıda
(Playwright + headless Chromium) uçtan uca çalışır -- tests/conftest.py,
api_servisi.py'yi ayrı bir alt süreçte (subprocess) canlı olarak ayağa
kaldırır (bkz. o dosyadaki "neden ayrı süreç" notu). playwright ana test
işini yavaşlatmasın diye ayrı requirements-tarayici.txt'dedir; kurulu
değilse bu testler yerelde atlanır. CI'daki ayrı tarayici işi Chromium'u
kurup testleri çalıştırır, atlanan test olursa başarısız olur ve ekran
görüntülerini (arayuz-ekran-goruntuleri artifact'ı) saklar. Yerelde:
pip install -r requirements-tarayici.txt && playwright install --with-deps chromium
TARAYICI_EKRAN_KLASORU=ekran_goruntuleri pytest -m tarayici -vruff check . # lint
ruff format . # biçimlendir
pre-commit install # her commit'te otomatik çalıştır.github/workflows/ci.yml, master'a push'ta ve her PR'da lint ve testleri (gerçek bir
PostgreSQL servis konteyneriyle) Python 3.12 (üretim, kilit dosyasıyla) ve
3.14 (geliştirme) için çalıştırır. guvenlik işi tüm git geçmişini
gitleaks ile (Türkçe değişken adlarını da tanıyan .gitleaks.toml) tarar,
sahte bir sırrın yakalandığını doğrular ve CycloneDX SBOM üretir. Kilit dosyaları
bagimlilik-taramasi.yml ile haftalık (Pazartesi) ve kilit değişince pip-audit'ten geçer. Commit, dal ve sır kuralları:
CONTRIBUTING.md.
Üretim ortamı Python 3.12'dir (.python-version, Docker imajı).
requirements.txt doğrudan bağımlılıkları sabitler; requirements.lock ise
bunların Linux/3.12 için tüm geçişli bağımlılıklarıyla hash'li çözümüdür.
Docker ve CI (3.12) pip install --require-hashes -r requirements.lock ile
kurar: her derleme bit bit aynı paketleri alır, yayında değiştirilmiş bir
paket kurulmaz. requirements.txt değişince kilit yeniden üretilir
(tests/test_bagimlilik_kilidi.py unutulursa yakalar):
python -m uv pip compile requirements.txt --python-version 3.12 \
--python-platform x86_64-manylinux_2_28 --generate-hashes --no-header -o requirements.lockUçuşa özel ERA5 indirmesi için gereken paketler (cdsapi, gcsfs, zarr)
isteğe bağlıdır (pip install -e ".[era5]") ve Docker imajına ayrı, hash'li
requirements-era5.lock ile kurulur. Bu kilit, ortak paketlerde ana kilitle
aynı sürümü tutması için ana kilidin pinleri kısıt verilerek üretilir
(requirements.lock'taki paket==sürüm satırları ana_kisit.txt'ye alınır):
python -m uv pip compile requirements-era5.txt -c ana_kisit.txt --python-version 3.12 \
--python-platform x86_64-manylinux_2_28 --generate-hashes --no-header -o requirements-era5.lock- TI1 ve gösterge ölçeği EDR değildir -- yukarıya bakın.
- Seviye seçimi barometrik irtifayla yapılır: seyirde altimetre 1013,25
hPa'ya ayarlı olduğu için ADS-B baro irtifası doğrudan ISA basınç
irtifasıdır; GPS (geo) irtifası sıcaklığa bağlı olarak yüzlerce metre sapar
(THY322'de medyan 225 m). Baro yoksa geo'ya düşülür ve
irtifa_kaynagisütunu işaretlenir. - ERA5 çözünürlüğünde Richardson < 0.25 neredeyse hiç görülmez: 1000 eşleşmiş seyir PIREP'inde en küçük Ri 0.32 idi; "dinamik kararsızlık" bayrağı bu çözünürlükte pratikte tetiklenmez. Ri yine de ayırt edici bir özelliktir (düşük Ri ile tek başına ROC-AUC 0.65).
- Kapsam kontrolü üç boyutludur: yatay (küp sınırı ±1°), zaman (EN
YAKIN gerçek zaman adımına en fazla 3 saat -- aralıklı indirilmiş küplerde
boşluktaki günler kapsam dışıdır) ve irtifa (bkz.
DIKEY_KAPSAM_TOLERANSI_ HPA). Kalkış/iniş ve yerdeki noktalar ile irtifası bilinmeyen noktalar bu yüzden TI1 almaz (haritada gri); seviye seçimindebaro_irtifa_mönceliklidir, yoksageo_irtifa_mkullanılır. flights_data4tablosundacallsignalanı 8 karakter, boşlukla doldurulmuş (padded) saklanır; eşleştirme bunu otomatik yapar.- Yatay deformasyon hesabı için veri kübünün ilgili zaman dilimindeki tüm enlem/boylam grid'ine ihtiyaç var (tek nokta yetmiyor).
config.EDR_OLCEKLENDIRME_KATSAYISI(0.27) seyir irtifasındaki gerçek IEM PIREP'leri + saatlik ERA5 ile (ml_ornekleri, 6218 örnek, 64 gün, Madde 2 fiziği)turbulans-edr-kalibrasyonkullanılarak kalibre edildi: gün bazlı bootstrap %95 GA[0.25, 0.28]; son 13 günlük zamansal testte MSE 0.076 (önceki 0.40: 0.082). Tanh ölçeği sabit ortalama tahmininden (MSE 0.067) daha iyi tahmin etmez: bir görselleştirme ölçeğidir, risk için ML olasılığı kullanılmalıdır. ABD hava sahası verisine dayanan, bölgeden bağımsız kaba bir kalibrasyondur; veri büyüdükçe yeniden çalıştırılmalıdır. Eski 0.23 değeri hatalı irtifa filtresiyle seçilmiş 300-400 feet'teki PIREP'lerle uydurulmuştu.- Proje gerçek bir uçuşla (OpenSky/Trino + gerçek
.ncverisi) uçtan uca test edildi. docker compose up --buildWSL2 (Ubuntu, Docker Engine) üzerinde uçtan uca denendi: imaj derlenir, API sağlıklı açılır, işçi konteyneri CDS'ten gerçek ERA5 dilimi indirir vedocker compose downsonrası önbellekler korunur.sigmet_dogrulama.py, SADECE ABD Aviation Weather Center'ın sorumlu olduğu hava sahaları için gerçek veri döner -- bu depodaki örnek veri kümesi (Türkiye) için örtüşme çıkmaması beklenen bir durumdur (yukarıya bakın).web/harita3d.htmlveweb/ucus_simulasyonu.html, ikisi de gerçek bir tarayıcıda (Playwright + headless Chromium) uçtan uca test EDİLDİ -- ikisinde de gerçek hatalar bulunup düzeltildi:ucus_simulasyonu.htmliçin CesiumJS'inimageryProviderseçeneğinin artık sessizce hiçbir katman eklememesi (bkz. "3D uçuş simülasyonu" bölümü),harita3d.htmliçin MapLibre 4.7.1'desetProjectionmetodunun HİÇ olmaması ve constructor'dan hemen sonra çağrılınca "Style is not done loading" vermesi (bkz. yukarıdaki "3D/canlı harita önyüzü" bölümü). Uçak "modelleri" arasındaki performans farkı (seyir hızı/yakıt akışı) halka açık, tipik değerlerdir -- resmi üretici performans verisi DEĞİLDİR.
Projenin geçmiş halinden bugüne kadarki tüm önemli değişiklikler için bkz. CHANGELOG.md.
Kaynak kodu: MIT. Kullanılan dış verilerin (OpenSky, ERA5, IEM, NOAA, openAIP, ...) lisansları, atıf metinleri ve ticari kullanım durumu: docs/VERI_KAYNAKLARI_VE_LISANSLAR.md. OpenSky verisi yalnızca araştırma ve ticari olmayan kullanım içindir.