-- ============================================================ -- 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;