256 lines
12 KiB
Markdown
256 lines
12 KiB
Markdown
# FR24 Noisemap — Полное описание системы
|
||
|
||
> Актуально на: 2026-04-21
|
||
|
||
## Назначение проекта
|
||
|
||
Система сбора, хранения и визуализации данных о воздушном движении над московскими аэропортами (SVO, DME, VKO, ZIA) для построения **карты шумового загрязнения** от авиации.
|
||
|
||
---
|
||
|
||
## Инфраструктура
|
||
|
||
**VM:** `fr24@192.168.2.67` (VM-FR24 в домашней сети, доступ через jump-host vpn-srv)
|
||
**Доступ:** `ssh -i ha_ssh_key -J vpn@185.130.212.192:3322 fr24@192.168.2.67`
|
||
**Docker Compose:** `/home/fr24/projects/fr24/compose/docker-compose.yml`
|
||
|
||
---
|
||
|
||
## Контейнеры (10 шт.)
|
||
|
||
### Слой хранения
|
||
|
||
| Контейнер | Порт | Назначение |
|
||
|---|---|---|
|
||
| `fr24-postgres` | 5432 | PostgreSQL 15 + PostGIS. Единая БД `fr24` со схемами: `fr24`, `fr24_ext`, `fr24_mart` |
|
||
| `fr24-backup` | — | Ежедневный pg_dump в `/backup/` |
|
||
|
||
### Слой сбора RTL-SDR
|
||
|
||
| Контейнер | Порт | Назначение |
|
||
|---|---|---|
|
||
| `fr24-capture` | — | Читает ADS-B поток с dump1090 (SBS port 30003). Пишет сырые пакеты в `fr24.raw_packets`. Retention 3 дня. |
|
||
| `fr24-preprocess` | — | Читает `fr24.raw_packets`, строит нормализованные `fr24.flights`, `fr24.tracks`, `fr24.track_points`. Поддерживает recovery после сбоя. |
|
||
|
||
### Слой внешних треков
|
||
|
||
| Контейнер | Порт | Назначение |
|
||
|---|---|---|
|
||
| `fr24-tracks-fr24` | 8001 | Загрузка треков из FR24 API (AeroAPI). `POST /run?date=YYYY-MM-DD` — вручную. Пишет в `fr24_ext.flight_tracks_fr24` + `fr24_ext.track_points_fr24`. Стоимость: ~40 кредитов/рейс. |
|
||
| `fr24-tracks-fa` | 8002 | Загрузка треков из FlightAware AeroAPI. `POST /run?date=YYYY-MM-DD` — вручную. Пишет в `fr24_ext.flight_tracks_fa` + `fr24_ext.track_points_fa`. Стоимость: $0.01/запрос. |
|
||
|
||
### Слой расписания и витрины
|
||
|
||
| Контейнер | Порт | Назначение |
|
||
|---|---|---|
|
||
| `fr24-schedule` | 8000 | Загрузка расписания из Яндекс Расписаний API. Запускается по cron T-1. Пишет в `fr24_ext.schedule`. Rate limit: ~100 запросов/час. |
|
||
| `fr24-mart` | 8003 | ETL-витрина. Объединяет расписание + треки из всех источников. Запускается по расписанию каждый час (T-1) и вручную `POST /run?date=YYYY-MM-DD`. Пишет в `fr24_mart.*`. |
|
||
|
||
### Слой отдачи данных и мониторинга
|
||
|
||
| Контейнер | Порт | Назначение |
|
||
|---|---|---|
|
||
| `fr24-api` | 8080 | REST API для фронтенда. Читает из `fr24`, `fr24_ext`, `fr24_mart`. Эндпоинты: расписание, мониторинг, data-sources. |
|
||
| `fr24-monitoring` | — | Мониторинг системы. Раз в минуту логирует: disk%, db_size, capture_lag, throughput, unprocessed. Алерты при деградации. |
|
||
|
||
---
|
||
|
||
## Схема базы данных
|
||
|
||
### Схема `fr24` — RTL-SDR данные (real-time)
|
||
|
||
```
|
||
fr24.raw_packets — сырые SBS-пакеты от dump1090
|
||
fr24.aircraft — реестр воздушных судов (icao24, callsign, reg)
|
||
fr24.flights — рейсы (callsign, started_at, ended_at)
|
||
fr24.tracks — треки рейсов
|
||
fr24.track_points — точки трека (lat, lon, altitude_m, speed, heading)
|
||
fr24.processing_state — курсор обработки (для recovery)
|
||
fr24.noise_results — результаты расчёта шума (устаревшее, мигрировано в mart)
|
||
```
|
||
|
||
### Схема `fr24_ext` — внешние источники
|
||
|
||
```
|
||
fr24_ext.schedule — расписание (Яндекс). ~1400 рейсов/день на 4 аэропорта.
|
||
Ключевые поля: schedule_id, flight_date, airport_iata,
|
||
direction, flight_number, origin_iata, destination_iata,
|
||
scheduled_at, thread_title (маршрут из Яндекса)
|
||
|
||
fr24_ext.flight_tracks_fr24 — заголовки треков FR24 API
|
||
fr24_ext.track_points_fr24 — точки треков FR24 (altitude_ft, gspeed_kt)
|
||
|
||
fr24_ext.flight_tracks_fa — заголовки треков FlightAware
|
||
fr24_ext.track_points_fa — точки треков FA (altitude_ft, gspeed_kt)
|
||
|
||
fr24_ext.load_state — состояние загрузок (для идемпотентности)
|
||
```
|
||
|
||
### Схема `fr24_mart` — финальная витрина
|
||
|
||
```
|
||
fr24_mart.flights — объединённые рейсы. Один рейс = одна строка.
|
||
Флаги: has_rtlsdr, has_fr24, has_fa
|
||
track_source: 'rtlsdr' | 'fr24' | 'fa' | null
|
||
Ссылки: fr24_track_id, fa_track_id, rtlsdr_flight_id
|
||
|
||
fr24_mart.track_points — точки трека с noise_score (расчёт по шумовой модели)
|
||
fr24_mart.noise_grid — агрегат по ячейкам 0.01°×0.01° (~1 км). AVG(noise_score)
|
||
fr24_mart.source_coverage — покрытие по источникам (% рейсов с треком)
|
||
```
|
||
|
||
---
|
||
|
||
## ETL-процессы
|
||
|
||
### 1. RTL-SDR pipeline (real-time)
|
||
```
|
||
Антенна → dump1090 SBS:30003 → fr24-capture → fr24.raw_packets
|
||
→ fr24-preprocess → fr24.flights/tracks/track_points
|
||
```
|
||
- **Покрытие:** ~230 рейсов/день (~9.6% от расписания)
|
||
- **Задержка:** 1-2 сек
|
||
- **Throughput:** ~3000 пакетов/5 мин
|
||
|
||
### 2. Schedule pipeline (ежедневно T-1)
|
||
```
|
||
Яндекс Расписания API → fr24-schedule → fr24_ext.schedule
|
||
```
|
||
- **4 аэропорта × 2 направления** = ~1400 рейсов/день
|
||
- **Rate limit:** ~100 запросов/час → ~30 запросов на один день
|
||
- **thread_title:** парсится из `thread.title` (маршрут "Москва → Санкт-Петербург")
|
||
|
||
### 3. FR24 tracks pipeline (по запросу)
|
||
```
|
||
FR24 AeroAPI → fr24-tracks-fr24 → fr24_ext.flight_tracks_fr24 + track_points_fr24
|
||
```
|
||
- Запуск: `POST http://fr24-tracks-fr24:8001/run?date=YYYY-MM-DD`
|
||
- **Лимит:** Explorer тариф, остаток ~50K кредитов (40 кредитов/рейс = ~1250 рейсов)
|
||
- **Хранится только по явной команде** (дорого)
|
||
|
||
### 4. FlightAware pipeline (по запросу)
|
||
```
|
||
FlightAware AeroAPI → fr24-tracks-fa → fr24_ext.flight_tracks_fa + track_points_fa
|
||
```
|
||
- Запуск: `POST http://fr24-tracks-fa:8002/run?date=YYYY-MM-DD`
|
||
- **Стоимость:** $0.01/запрос, ~$28/день при полной загрузке
|
||
- Rate limit: 429 после ~5-10 быстрых запросов, Retry-After 60с
|
||
|
||
### 5. Mart builder (каждый час автоматически, T-1)
|
||
```
|
||
fr24_ext.schedule + fr24.flights + fr24_ext.flight_tracks_fr24 + fr24_ext.flight_tracks_fa
|
||
→ build_mart.py → fr24_mart.flights + track_points + noise_grid + source_coverage
|
||
```
|
||
|
||
**Логика мэтчинга (приоритет RTL-SDR > FR24 > FA):**
|
||
|
||
1. **RTL-SDR:** `flight_number` (IATA `'SU 1057'`) → конвертируется в ICAO callsign (`'AFL1057'`) → поиск в `fr24.flights.callsign`
|
||
2. **FR24:** числовой номер рейса (`6807`) + маршрут (ICAO аэропортов → IATA через словарь) → поиск в `fr24_ext.flight_tracks_fr24`
|
||
3. **FA:** числовой номер рейса + маршрут → поиск в `fr24_ext.flight_tracks_fa`
|
||
|
||
**Проблема мэтчинга (⚠️ в работе):**
|
||
- RTL-SDR: требует словарь `AIRLINE_IATA_TO_ICAO` (AFL=SU, SDM=FV и т.д.)
|
||
- FA: хранит ICAO ident (`CSN342`), расписание IATA (`CZ 342`) → числовой матч
|
||
- Словарь аэропортов `ICAO_TO_IATA` неполный (~40 аэропортов)
|
||
|
||
### 6. Шумовая модель
|
||
```
|
||
track_points → altitude_to_noise_db(alt_ft, aircraft_type) → noise_score
|
||
→ AGG по ячейкам 0.01° → noise_grid
|
||
```
|
||
|
||
**Зоны:**
|
||
- 0-2 км: Критический (>75 dB)
|
||
- 2-5 км: Высокий (65-75 dB)
|
||
- 5-7 км: Средний (55-65 dB)
|
||
- 7-9 км: Низкий (45-55 dB)
|
||
- >9 км: Фоновый (<45 dB)
|
||
|
||
---
|
||
|
||
## UI (фронтенд)
|
||
|
||
Фронтенд: Flask + Leaflet.js, доступен через nginx reverse proxy.
|
||
|
||
### Страницы
|
||
|
||
#### `/` — Карта шумового загрязнения
|
||
- **Тепловая карта** (Leaflet heatmap layer) по данным `fr24_mart.noise_grid`
|
||
- **Аэропорты** SVO/DME/VKO/ZIA маркерами
|
||
- **Зоны влияния** 2/5/7/9 км (цветные круги)
|
||
- **Выбор даты** — слайдер или датепикер
|
||
- **Легенда** шума
|
||
|
||
#### `/schedule` — Расписание рейсов
|
||
- Таблица рейсов из `fr24_mart.flights` с маршрутами
|
||
- **Фильтры:** аэропорт, направление, дата
|
||
- Маршрут отображается из `thread_title` (Яндекс) — "Москва → Санкт-Петербург"
|
||
- **CSV экспорт** — выгрузка с городами вместо IATA-кодов
|
||
- Иконки источника трека (RTL/FR24/FA)
|
||
|
||
#### `/monitoring` — Мониторинг системы
|
||
- Capture lag, throughput, unprocessed packets
|
||
- DB size, disk usage
|
||
- Статус контейнеров
|
||
- График активности за последние 24ч
|
||
|
||
#### `/data-sources` — Покрытие источниками
|
||
- Статистика по `fr24_mart.source_coverage`
|
||
- % рейсов с треком по каждому источнику
|
||
- Топ авиакомпаний, топ маршрутов
|
||
- Загрузка аэропортов
|
||
|
||
### API эндпоинты (fr24-api :8080)
|
||
|
||
```
|
||
GET /api/schedule/data?date_from=&date_to=&airport=&direction=
|
||
GET /api/monitoring
|
||
GET /api/data-sources/coverage
|
||
GET /api/data-sources/quality
|
||
GET /api/data-sources/top-airlines
|
||
GET /api/data-sources/top-routes
|
||
GET /api/data-sources/airport-load
|
||
```
|
||
|
||
---
|
||
|
||
## Текущий статус данных (на 21.04.2026)
|
||
|
||
| Что | Количество |
|
||
|---|---|
|
||
| Расписание в fr24_ext | 01.04 – 19.04.2026 (~26K рейсов) |
|
||
| FR24 треки | 1 рейс (FV6807, тест) |
|
||
| FA треки | 5 рейсов (CSN, тест) |
|
||
| RTL-SDR рейсы | 19–21.04 (~730 рейсов) |
|
||
| Витрина fr24_mart | 01.04 только (1399 рейсов, 1 с треком) |
|
||
| Noise grid | 688 ячеек за 01.04 |
|
||
|
||
---
|
||
|
||
## Известные ограничения и backlog
|
||
|
||
| # | Проблема | Приоритет |
|
||
|---|---|---|
|
||
| 1 | Мэтчинг RTL-SDR: IATA→ICAO конвертация авиакомпаний не реализована | 🔴 Высокий |
|
||
| 2 | Мэтчинг FA: ICAO ident в БД vs IATA в расписании | 🔴 Высокий |
|
||
| 3 | DDL: `origin_icao`/`destination_icao` VARCHAR(5) в flight_tracks_fa | 🔴 Высокий |
|
||
| 4 | Словарь ICAO_TO_IATA аэропортов неполный (~40 из нужных 200+) | 🟡 Средний |
|
||
| 5 | Яндекс backfill 06–19.04 не завершён (rate limit 429) | 🟡 Средний |
|
||
| 6 | Витрина не содержит данных за 02–19.04 | 🟡 Средний |
|
||
| 7 | Duration рейсов: только 6.6% заполнено | 🟢 Низкий |
|
||
|
||
---
|
||
|
||
## Ключи и конфиги
|
||
|
||
| Сервис | Переменная | Где |
|
||
|---|---|---|
|
||
| FR24 API | `FR24_API_KEY` | `.env` на VM |
|
||
| FlightAware | `FLIGHTAWARE_API_KEY` | `.env` на VM |
|
||
| Яндекс Расписания | `YANDEX_API_KEY` | `.env` на VM |
|
||
| PostgreSQL | `POSTGRES_PASSWORD=change-me` | docker-compose |
|
||
|
||
FR24 Explorer: остаток **~50 486 кредитов** из 120K (промо до 31.05.2026)
|
||
FlightAware: потрачено **$0.05** из pay-per-use
|
||
Яндекс: **rate limit** сбросится ~23:30 UTC 21.04
|