✈️ Карта шумового загрязнения — Прототип v0.2
Веб-приложение для визуализации шумового загрязнения от воздушных судов
над Московской областью на основе данных Flightradar24 API.
🚀 Быстрый старт
cd tasks/flightradar24
. venv/bin/activate
pip install -r prototype/requirements.txt
cd prototype
# Сгенерировать тестовые данные (50 синтетических рейсов)
python generate_sample_data.py
# Запустить сервер
python app.py
# → http://localhost:5555
# → https://openclaw.mva154.duckdns.org/noisemap/ (через nginx)
С реальным API:
# Скопировать шаблон и заполнить ключи
cp .env.example .env
# FLIGHTRADAR24_API_KEY — FR24 Explorer (треки, снимки)
# YANDEX_RASP_API_KEY — Яндекс.Расписания (табло аэропортов, стратегия Б)
python app.py
📁 Структура
prototype/
├── app.py # Flask backend + REST API
├── noise_model.py # ⚙️ Модель шума (калибровочные параметры здесь)
├── fr24_client.py # Клиент Flightradar24 API (с кэшированием)
├── generate_sample_data.py # Генератор синтетических треков
├── fetch_airport.py # Загрузка треков по аэропорту (стратегия А)
├── fetch_airport_offset.py # Загрузка со смещением времени (стратегия А+)
├── fetch_svo_tracks.py # Загрузка только SVO треков
├── fetch_tracks.py # Загрузка треков (общий скрипт)
├── index.html # Фронтенд (OpenLayers + Turf.js)
├── requirements.txt
├── .env.example
└── data/
├── flights_SVO_2026-03-21.json # Реальные данные SVO 21.03
├── flights_DME_2026-03-21.json # Реальные данные DME 21.03
├── flights_VKO_2026-03-21.json # Реальные данные VKO 21.03
├── flights_ZIA_2026-03-21.json # Реальные данные ZIA 21.03
├── flights_SVO_2026-03-20_offset90m.json # SVO 20.03 со смещением +1.5ч
├── flights_DME_2026-03-20_offset90m.json # DME 20.03 со смещением +1.5ч
├── flights_VKO_2026-03-20_offset90m.json # VKO 20.03 со смещением +1.5ч
├── flights_ZIA_2026-03-20_offset90m.json # ZIA 20.03 со смещением +1.5ч
├── sample_flights.json # Fallback (синтетика или последняя загрузка)
├── cache_SVO/ # Кэш треков SVO
├── cache_DME/ # Кэш треков DME
├── cache_VKO/ # Кэш треков VKO
├── cache_ZIA/ # Кэш треков ZIA
└── cache/ # Общий кэш API запросов
Сервер автоматически объединяет все файлы flights_*.json при старте.
🔌 REST API
| Метод | Путь | Описание |
|---|---|---|
| GET | / |
Веб-карта |
| GET | /api/flights |
Рейсы с шумовыми данными |
| GET | /api/noise-config |
Параметры модели шума |
| GET | /api/airports |
Аэропорты региона |
| GET | /api/stats |
Статистика |
| GET | /api/usage |
Использование кредитов FR24 |
| GET | /api/live |
Live позиции (требует API ключ) |
| GET | /api/help |
Документация API |
Параметры /api/flights
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
limit |
int | 100 | Макс. рейсов |
min_alt |
int | 0 | Мин. высота (футы) |
max_alt |
int | 50000 | Макс. высота (футы) |
type |
str | all | departure / arrival / all |
airport |
str | all | SVO / DME / VKO / ZIA / all |
date_from |
str | — | Начало периода (YYYY-MM-DD) |
date_to |
str | — | Конец периода (YYYY-MM-DD) |
📡 Стратегии загрузки данных
Стратегия А — Снимки позиций (текущая)
Принцип: делаем снимки всех самолётов над МО в фиксированные моменты времени, затем для каждого найденного рейса загружаем полный трек и обрезаем до bbox МО.
Скрипты:
# Загрузить данные за дату
python fetch_airport.py SVO 2026-03-21
# Загрузить со смещением (для увеличения охвата)
python fetch_airport_offset.py SVO 2026-03-21 1.5
Параметры:
- Интервал снимков: 3 часа (00:00, 03:00, 06:00 ... 21:00 UTC)
- bbox МО:
54.0–57.0°N, 35.5–40.5°E - Endpoint снимков:
/historic/flight-positions/full - Endpoint треков:
/flight-tracks
Расход кредитов (1 аэропорт, 1 день):
| Операция | Кол-во | Кредитов |
|---|---|---|
| Снимки (8 шт × ~10 рейсов) | ~80 | ~80 |
| Треки (~30–45 уник. рейсов) | ~40 | ~3 000 |
| Итого | ~3 100 |
Охват: ~10% реальных рейсов за день (большинство пролетают между снимками)
Улучшение охвата через смещение: Запуск стратегии А дважды — основной (00:00, 03:00...) и со смещением +1.5ч (01:30, 04:30...) даёт интервал 1.5ч вместо 3ч → охват ~20%, стоимость ×2.
Стратегия Б — Табло → Треки (планируемая)
Принцип: берём полный список рейсов за день из табло аэропорта (парсинг сайта), для каждого рейса ищем fr24_id через live API и загружаем трек над МО.
Алгоритм:
- Парсим табло вылетов/прилётов с сайта (svo.aero, Яндекс.Расписания и др.) — бесплатно
- По callsign ищем fr24_id через
/live/flight-positions/full?callsign=SU1234— 1 кредит/рейс - Загружаем трек
/flight-tracks?flight_id=XXX— платим за полный трек, используем только МО-часть - Фильтруем точки трека по bbox МО
Расход кредитов (1 аэропорт, 1 день):
| Операция | Кол-во | Кредитов |
|---|---|---|
| Поиск fr24_id по callsign | ~330 | ~330 |
| Треки (полный маршрут) | ~330 | ~24 000 |
| Итого SVO за 1 день | ~24 500 | |
| 4 аэропорта за 1 день | ~80 000 | |
| 4 аэропорта за 7 дней | ~560 000 ⚠️ |
Охват: ~100% рейсов за день
Точность трека: 10 секунд между точками (отличная)
Ограничения:
- Нет API FR24 для списка рейсов по дате → нужен парсинг сайта аэропорта
- Высокая стоимость:
/flight-tracksвозвращает весь маршрут (~700 точек), временная фильтрация на стороне API не поддерживается (проверено) - При промо 120k: реально покрыть 3–5 дней × 1 аэропорт или 1 день × 4 аэропорта
Примечание о holding patterns: Небольшая доля рейсов (~5–10% прилётов) выполняет зоны ожидания над МО — кружит перед посадкой при загруженности аэропорта или плохой погоде. Для таких рейсов трек над МО значительно длиннее обычного.
Сравнительная таблица стратегий
| Критерий | Стратегия А | Стратегия Б |
|---|---|---|
| Охват рейсов | ~10–20% | ~100% |
| Точность трека | 10 сек | 10 сек |
| Стоимость/день/аэропорт | ~3 100 кредитов | ~24 500 кредитов |
| 7 дней × 4 аэропорта | ~87 000 ✅ | ~560 000 ❌ |
| Реализация | Готово | Требует парсинг табло |
| Статус | ✅ Реализована | ⏳ Планируется |
🔊 Модель шума
Физическая основа
Шум распространяется сферически. Уровень зависит от реального 3D-расстояния R до наблюдателя. На карте отображается горизонтальный катет D (теорема Пифагора):
самолёт ●
|\
H | \ R ← граница зоны (гипотенуза)
| \
земля ●──────●──────● наблюдатель
D (катет = ширина зоны на карте)
D = √(R² − H²), если H < R, иначе зона не видна
Следствия:
- Чем выше самолёт — тем уже зоны на карте
- При H ≥ R — зона полностью исчезает
- При H = 0 — ширина зоны = R (максимум)
Пример для H = 3.5 км:
| Зона | R_outer | D_outer | R_inner | D_inner | Вид |
|---|---|---|---|---|---|
| Критический | 2 км | — (H>R) | 0 | — | ❌ |
| Сильный | 5 км | 3.57 км | 2 | 0 | ✅ круг |
| Средний | 7 км | 6.06 км | 5 | 3.57 | ✅ кольцо |
| Низкий | 11 км | 10.43 км | 7 | 6.06 | ✅ кольцо |
Таблица зон
| Зона | R (сфера) | Цвет | Прозрачность |
|---|---|---|---|
| Критический | < 2 км | 🔴 #FF3333 | 0.55 |
| Сильный | 2–5 км | 🟠 #FF8800 | 0.40 |
| Средний | 5–7 км | 🟡 #FFCC00 | 0.28 |
| Низкий | 7–11 км | 🟢 #88DD00 | 0.18 |
| Нет шума | > 11 км | — | — |
🎛 Калибровка
Все параметры вынесены в начало noise_model.py:
NOISE_ZONES = [
{
"id": "zone_critical",
"R_inner": 0.0, # км — внутренняя граница сферы
"R_outer": 2.0, # км — внешняя граница сферы ← меняй здесь
"color": "#FF3333",
"opacity": 0.55,
},
...
]
После изменения — перезапустить python app.py.
🗺️ Карта — функциональность
Треки
- Цвет — градиент по высоте: 🔴 0 м → 🟡 4 250 м → 🟢 8 500+ м
- Hover → tooltip с параметрами точки
- Клик → детали рейса в боковой панели
- Переключатель ✈ Треки — скрыть/показать треки (зоны остаются)
- Трек отображается поверх шумовых зон (zIndex 50)
Детали рейса (боковая панель)
- 🛫/🛬 тип рейса + callsign
- Номер рейса, тип ВС, регистрация
- Маршрут с названиями городов:
Сочи (AER)→Москва (SVO) - Дата полёта
- Время входа/выхода из Московской области (МСК, UTC+3)
- Высота (м), скорость (км/ч), уровень шума (дБ)
Шумовые зоны
- Реальные географические полигоны (Turf.js
buffer+difference) - Строятся посегментно с учётом высоты каждого сегмента
- Чекбоксы для включения/отключения каждой зоны
Фильтры
- Аэропорт: Все / SVO / DME / VKO / ZIA
- Тип рейса: Все / Вылеты / Прилёты
- Высота: слайдеры в метрах (0–13 000 м)
- Период: date picker (date_from / date_to)
Флажки (маркеры)
- Кнопка 📍 Добавить → клик на карту → ставит флажок
- Клик на флажок → удалить
- Двойной клик на название в списке → переименовать
- Несколько флажков одновременно, разные цвета
Линейка
- Кнопка 📏 Включить → кликать по точкам → тянется линия
- Двойной клик → завершить (автовыключение)
- Показывает итог и разбивку по сегментам (формула Haversine)
- 🗑 Сбросить → очистить
📊 Текущие данные
| Файл | Дата | Аэропорт | Рейсов | Точек |
|---|---|---|---|---|
| flights_SVO_2026-03-21.json | 21.03 | SVO | 33 | ~6 000 |
| flights_DME_2026-03-21.json | 21.03 | DME | 15 | ~3 000 |
| flights_VKO_2026-03-21.json | 21.03 | VKO | 21 | ~4 000 |
| flights_ZIA_2026-03-21.json | 21.03 | ZIA | 1 | ~46 |
| flights_SVO_2026-03-20_offset90m.json | 20.03 +1.5ч | SVO | — | — |
| flights_DME_2026-03-20_offset90m.json | 20.03 +1.5ч | DME | — | — |
| flights_VKO_2026-03-20_offset90m.json | 20.03 +1.5ч | VKO | — | — |
| flights_ZIA_2026-03-20_offset90m.json | 20.03 +1.5ч | ZIA | — | — |
Итого: 147 рейсов / 29 487 точек / 2 дня / 4 аэропорта
💳 Расход кредитов FR24 API
Тариф Explorer: 60 000 кредитов/месяц (промо 120 000 до 31.05.2026)
На 22.03.2026 потрачено (приблизительно):
historic/flight-positions/light(тесты): ~1 717historic/flight-positions/full(данные): ~5 564flight-tracks(треки): ~8 880- Итого: ~16 161 кредитов (~13% промо-лимита)
🗓️ Статус и план
| Шаг | Статус | Описание |
|---|---|---|
| Шаг 0 | ✅ Готово | UI, синтетика, модель шума, линейка, флажки |
| Шаг 1 | ✅ Готово | Sandbox проверка, исправление bounds |
| Шаг 2 | ✅ Готово | Production данные (4 аэропорта, 2 дня, стратегия А) |
| Шаг 3 | ✅ Готово | Стратегия Б v2: 111 новых треков SVO 21.03, итого 258 рейсов / 50 282 точки |
Бэклог
- Стратегия Б: парсинг табло + полный охват рейсов
- Фильтр по дате в UI (переключение между загруженными днями)
- Тепловая карта накопленного шума по регионам
- Фильтр по авиакомпаниям и типам ВС
- Учёт времени суток (ночные полёты)
- Привязка к санитарным нормам (СН 2.2.4/2.1.8.562-96)
- Экспорт зон в GeoJSON/KML
- Оптимизация производительности (много треков → тормоза браузера)