auto-sync: 2026-04-26 11:30:01
This commit is contained in:
178
tasks/flightradar24/analysis/adsb_quality_metrics.sql
Normal file
178
tasks/flightradar24/analysis/adsb_quality_metrics.sql
Normal file
@@ -0,0 +1,178 @@
|
||||
-- ============================================================
|
||||
-- ADS-B Track Quality Metrics
|
||||
-- Замени: 56.121, 37.216 — координаты антенны
|
||||
-- Замени: 150 — радиус ЗУП в км (начни с 150)
|
||||
-- ============================================================
|
||||
|
||||
|
||||
-- ============================================================
|
||||
-- 0. Вспомогательная функция: расстояние от точки до антенны (км)
|
||||
-- Используется PostGIS ST_Distance с geography
|
||||
-- ============================================================
|
||||
|
||||
|
||||
-- ============================================================
|
||||
-- 1. ГИСТОГРАММА РАССТОЯНИЙ — для определения ЗУП
|
||||
-- Показывает плотность точек по кольцам от антенны
|
||||
-- ============================================================
|
||||
WITH antenna AS (
|
||||
SELECT ST_SetSRID(ST_MakePoint(37.216, 56.121), 4326)::geography AS pt
|
||||
),
|
||||
point_distances AS (
|
||||
SELECT
|
||||
tp.track_id,
|
||||
ST_Distance(tp.geom::geography, a.pt) / 1000 AS dist_km
|
||||
FROM fr24.track_points tp, antenna a
|
||||
WHERE tp.observed_at >= NOW() - INTERVAL '7 days'
|
||||
)
|
||||
SELECT
|
||||
(dist_km / 10)::int * 10 AS dist_bucket_km, -- кольца по 10 км
|
||||
COUNT(*) AS point_count,
|
||||
COUNT(DISTINCT track_id) AS track_count
|
||||
FROM point_distances
|
||||
GROUP BY dist_bucket_km
|
||||
ORDER BY dist_bucket_km;
|
||||
|
||||
|
||||
-- ============================================================
|
||||
-- 2. МЕТРИКИ ПО ТРЕКАМ (M1–M4) за последние 7 дней
|
||||
-- Только треки с точками в ЗУП
|
||||
-- ============================================================
|
||||
WITH antenna AS (
|
||||
SELECT ST_SetSRID(ST_MakePoint(37.216, 56.121), 4326)::geography AS pt
|
||||
),
|
||||
-- Точки с расстоянием от антенны
|
||||
pts AS (
|
||||
SELECT
|
||||
tp.track_id,
|
||||
tp.track_point_id,
|
||||
tp.observed_at,
|
||||
tp.geom,
|
||||
tp.ground_speed_kt,
|
||||
tp.heading_deg,
|
||||
ST_Distance(tp.geom::geography, a.pt) / 1000 AS dist_km
|
||||
FROM fr24.track_points tp, antenna a
|
||||
WHERE tp.observed_at >= NOW() - INTERVAL '7 days'
|
||||
),
|
||||
-- Только точки в ЗУП
|
||||
zup_pts AS (
|
||||
SELECT * FROM pts WHERE dist_km <= 150
|
||||
),
|
||||
-- Последовательные пары точек для M1/M2/скорость
|
||||
pairs AS (
|
||||
SELECT
|
||||
track_id,
|
||||
observed_at,
|
||||
dist_km,
|
||||
ground_speed_kt,
|
||||
-- расстояние до следующей точки (м)
|
||||
ST_Distance(
|
||||
geom::geography,
|
||||
LEAD(geom) OVER (PARTITION BY track_id ORDER BY observed_at)::geography
|
||||
) AS step_dist_m,
|
||||
-- временной интервал до следующей точки (сек)
|
||||
EXTRACT(EPOCH FROM (
|
||||
LEAD(observed_at) OVER (PARTITION BY track_id ORDER BY observed_at) - observed_at
|
||||
)) AS step_dt_sec
|
||||
FROM zup_pts
|
||||
),
|
||||
-- Производная скорость между точками
|
||||
pairs_with_speed AS (
|
||||
SELECT *,
|
||||
CASE WHEN step_dt_sec > 0 THEN step_dist_m / step_dt_sec ELSE NULL END AS computed_speed_ms
|
||||
FROM pairs
|
||||
WHERE step_dist_m IS NOT NULL AND step_dt_sec IS NOT NULL
|
||||
),
|
||||
-- Агрегация по треку
|
||||
track_metrics AS (
|
||||
SELECT
|
||||
track_id,
|
||||
-- M3: кол-во точек в ЗУП
|
||||
COUNT(*) AS n_zup,
|
||||
-- M1: медианное расстояние между точками
|
||||
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY step_dist_m) AS median_step_m,
|
||||
MAX(step_dist_m) AS max_step_m,
|
||||
-- M2: медианный интервал между точками
|
||||
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY step_dt_sec) AS median_dt_sec,
|
||||
MAX(step_dt_sec) AS max_gap_sec,
|
||||
-- gap rate: доля интервалов > 30 сек
|
||||
ROUND(
|
||||
SUM(CASE WHEN step_dt_sec > 30 THEN 1 ELSE 0 END)::numeric
|
||||
/ NULLIF(COUNT(*), 0), 3
|
||||
) AS gap_rate,
|
||||
-- M4: outlier ratio — вычисленная скорость > 350 м/с (Mach 1)
|
||||
ROUND(
|
||||
SUM(CASE WHEN computed_speed_ms > 350 THEN 1 ELSE 0 END)::numeric
|
||||
/ NULLIF(COUNT(*), 0), 3
|
||||
) AS outlier_ratio,
|
||||
MIN(dist_km) AS min_dist_km,
|
||||
MAX(dist_km) AS max_dist_km
|
||||
FROM pairs_with_speed
|
||||
GROUP BY track_id
|
||||
HAVING COUNT(*) >= 5 -- минимальный значимый трек
|
||||
),
|
||||
-- ============================================================
|
||||
-- 3. TRACK QUALITY SCORE (TQS)
|
||||
-- TQS = 0.3*(1-gap_rate) + 0.3*(1-outlier_ratio)
|
||||
-- + 0.2*min(n_zup/20, 1) + 0.2*(coverage_ratio ≈ 1 - gap_rate)
|
||||
-- ============================================================
|
||||
tqs AS (
|
||||
SELECT
|
||||
track_id,
|
||||
n_zup,
|
||||
median_step_m,
|
||||
median_dt_sec,
|
||||
max_gap_sec,
|
||||
gap_rate,
|
||||
outlier_ratio,
|
||||
min_dist_km,
|
||||
max_dist_km,
|
||||
ROUND(
|
||||
0.3 * (1 - COALESCE(gap_rate, 0))
|
||||
+ 0.3 * (1 - COALESCE(outlier_ratio, 0))
|
||||
+ 0.2 * LEAST(n_zup::numeric / 20, 1)
|
||||
+ 0.2 * (1 - COALESCE(gap_rate, 0)) -- coverage ≈ 1 - gap_rate
|
||||
, 3) AS tqs
|
||||
FROM track_metrics
|
||||
)
|
||||
SELECT * FROM tqs
|
||||
ORDER BY tqs DESC;
|
||||
|
||||
|
||||
-- ============================================================
|
||||
-- 4. RECEPTION HEALTH INDEX (RHI) — итоговый по дням
|
||||
-- Мониторинг деградации антенны/приёмника во времени
|
||||
-- ============================================================
|
||||
WITH antenna AS (
|
||||
SELECT ST_SetSRID(ST_MakePoint(37.216, 56.121), 4326)::geography AS pt
|
||||
),
|
||||
daily AS (
|
||||
SELECT
|
||||
DATE(tp.observed_at) AS day,
|
||||
COUNT(DISTINCT tp.track_id) AS tracks_total,
|
||||
COUNT(*) AS points_total,
|
||||
-- точки в ЗУП
|
||||
COUNT(*) FILTER (
|
||||
WHERE ST_Distance(tp.geom::geography, a.pt) / 1000 <= 150
|
||||
) AS points_in_zup,
|
||||
COUNT(DISTINCT tp.track_id) FILTER (
|
||||
WHERE ST_Distance(tp.geom::geography, a.pt) / 1000 <= 150
|
||||
) AS tracks_in_zup
|
||||
FROM fr24.track_points tp, antenna a
|
||||
WHERE tp.observed_at >= NOW() - INTERVAL '14 days'
|
||||
GROUP BY DATE(tp.observed_at)
|
||||
)
|
||||
SELECT
|
||||
day,
|
||||
tracks_total,
|
||||
tracks_in_zup,
|
||||
points_total,
|
||||
points_in_zup,
|
||||
ROUND(points_in_zup::numeric / NULLIF(points_total, 0), 3) AS zup_ratio,
|
||||
-- RHI: нормализуем tracks_in_zup на медиану по периоду
|
||||
ROUND(
|
||||
tracks_in_zup::numeric
|
||||
/ NULLIF(AVG(tracks_in_zup) OVER (), 0)
|
||||
, 3) AS rhi
|
||||
FROM daily
|
||||
ORDER BY day;
|
||||
Reference in New Issue
Block a user