Машинний переклад, не перевірений носієм мови. Еталоном є англійська версія.

Довіра до приймача та морська галузьРедагувати на GitHubДжерело: docs/RECEIVER-TRUST.md

Довіра до приймача: оцінювання реального журналу приймача GNSS

kshana receiver-trust читає журнал реального приймача глобальної навігаційної супутникової системи (GNSS), проганяє над ним монітори довіри епоха за епохою та каже, коли і чому визначення положення приймачем перестало бути надійним. Він також може оцінити журнал за подіями та прогнозами, які ви заявляєте до прогону: чи було кожну подію виявлено вчасно і чи змодельоване падіння відношення потужності несівної до густини шуму (C/N0) узгоджується з тим, що виміряв приймач.

Спостережувані величини — власні для приймача; монітори та їхні пороги належать рушієві й вам. Кожен результат несе цю позначку, SHA-256 журналу та кожен поріг, з яким працював, тож прогін можна повторити й перевірити.

Для судна на ходу, з живою оцінкою та необов'язковим шлюзом перед системою карт див. MARITIME-TRUST.md.

Власний прапорець спуфінгу приймача, зіставлений із тривогами Kshana, за реальним прогоном рушія v0.40.0 на вигаданому журналі UBX (200 епох із частотою 1 Hz). C/N0 падає на 20 dB на інтервалах від 80 до 90 s і від 120 до 130 s; приймач позначає інтервали від 120 до 130 s і від 160 до 165 s. Із 140 епох, порівняних після калібрування, в 11 позначили обидва, в 6 лише приймач, в 11 лише Kshana і в 112 жоден. Жодна зі сторін не є еталонною істиною, а узгодженість не є валідацією. Лише консультативно: результат аналізу від дослідницького та інженерного інструмента; це не навігаційне обладнання із затвердженням типу і не послуга забезпечення безпеки життя.Власний прапорець спуфінгу приймача, зіставлений із тривогами Kshana, за реальним прогоном рушія v0.40.0 на вигаданому журналі UBX (200 епох із частотою 1 Hz). C/N0 падає на 20 dB на інтервалах від 80 до 90 s і від 120 до 130 s; приймач позначає інтервали від 120 до 130 s і від 160 до 165 s. Із 140 епох, порівняних після калібрування, в 11 позначили обидва, в 6 лише приймач, в 11 лише Kshana і в 112 жоден. Жодна зі сторін не є еталонною істиною, а узгодженість не є валідацією. Лише консультативно: результат аналізу від дослідницького та інженерного інструмента; це не навігаційне обладнання із затвердженням типу і не послуга забезпечення безпеки життя.

Запуск#

kshana receiver-trust examples/receiver-trust/session.toml

Це записує session.result.json, session.trust.csv (один рядок на епоху) і session.trust.svg (середнє C/N0 за часом зі станом довіри під ним) поруч зі сценарієм і друкує однорядковий вердикт. Приклад журналу є синтетичним, створеним, щоб показати формат; націльте path на журнал власного приймача.

Оцінка довіри за один синтетичний перехід, за реальним прогоном рушія v0.40.0 на examples/maritime-trust (вигаданий журнал NMEA порома на маршруті Таллінн — Гельсінкі, 3001 епох при 1 Hz). Три доріжки ділять одну вісь часу. Вгорі: відстань між положенням, яке повідомляє приймач, і справжнім положенням судна, що лишається в межах кількох метрів приблизно до 1576 s, коли заскриптоване відведення положення в журналі відтягує його, а приймач і далі повідомляє чинне визначення місця. Посередині: оцінка довіри від 0 до 100, не обчислювана протягом перших 300 s калібрування, у смузі nominal (щонайменше 90) до відведення, потім падає через смугу degraded (щонайменше 55) у смугу untrusted. Внизу: смуга кожної епохи як кольорова стрічка з її назвою. Оцінка є консультативною. Консультативне програмне забезпечення, не навігаційне обладнання із затвердженням типу (IEC 61108, IEC 61162): відповідальність за навігацію судна залишається на операторі. Журнал вигаданий, щоб показати формат і монітори; це не вимірювання і воно нічого не каже про те, як працював би будь-який приймач.Оцінка довіри за один синтетичний перехід, за реальним прогоном рушія v0.40.0 на examples/maritime-trust (вигаданий журнал NMEA порома на маршруті Таллінн — Гельсінкі, 3001 епох при 1 Hz). Три доріжки ділять одну вісь часу. Вгорі: відстань між положенням, яке повідомляє приймач, і справжнім положенням судна, що лишається в межах кількох метрів приблизно до 1576 s, коли заскриптоване відведення положення в журналі відтягує його, а приймач і далі повідомляє чинне визначення місця. Посередині: оцінка довіри від 0 до 100, не обчислювана протягом перших 300 s калібрування, у смузі nominal (щонайменше 90) до відведення, потім падає через смугу degraded (щонайменше 55) у смугу untrusted. Внизу: смуга кожної епохи як кольорова стрічка з її назвою. Оцінка є консультативною. Консультативне програмне забезпечення, не навігаційне обладнання із затвердженням типу (IEC 61108, IEC 61162): відповідальність за навігацію судна залишається на операторі. Журнал вигаданий, щоб показати формат і монітори; це не вимірювання і воно нічого не каже про те, як працював би будь-який приймач.

Наведена вище діаграма — демонстрація судна з MARITIME-TRUST.md: вигаданий журнал, консультативна оцінка.

Той самий сценарій запускається з Python (kshana.receiver_trust(toml)), з пакета WebAssembly (receiver_trust(toml), із журналом у тексті) і з інструмента assess_receiver_log сервера Model Context Protocol (MCP).

Журнали, які він читає#

format Джерело Що читається
ubx Двійковий формат u-blox NAV-SAT: C/N0, висота та азимут за супутником, NAV-PVT: положення, MON-RF: автоматичне регулювання підсилення (AGC) та індикатор глушіння jamInd, тиждень NAV-TIMEGPS і власні прапорці приймача: NAV-STATUS spoofDetState та SEC-SIG (self_report, див. RECEIVER-PROTOCOLS.md)
rinex Файл спостережень RINEX 3 коди S (C/N0) за супутником і сигналом; з бортовим навігаційним файлом (nav) — псевдодальності для власного розв'язку рушія
android CSV Android GnssLogger рядки Raw: C/N0 і AgcDb за супутником; рядки Fix: положення
nmea Текст NMEA 0183 GSV: відношення сигнал/шум за супутником (дБ-Гц, з ідентифікатором сигналу 4,10 або без нього) та його висота й азимут, GSA: геометричний чинник DOP і використані супутники, GGA і RMC: час і положення
sbf Двійковий формат Septentrio (0,38, лише читання) положення PVTGeodetic, C/N0 за супутником і сигналом із MeasEpoch, кількість діапазонів із RFStatus; див. RECEIVER-PROTOCOLS.md
rtklib-pos Файл розв'язків RTKLIB (.pos) час, положення (широта/довгота або ECEF, перетворені) і використані супутники за епохою; файли в градусах-хвилинах-секундах відхиляються з повідомленням
novatel Журнали NovAtel OEM7 у форматі ASCII або двійковому положення BESTPOS (лише обчислений розв'язок), C/No RANGE за супутником і сигналом; прапорці глушника RXSTATUS стають self_report епохи (стан глушіння 2, коли приймач сигналізує про глушник, 1, коли ні; прапорця спуфінгу в RXSTATUS не існує), зіставлені з тривогами Kshana порівнянням receiver-self-report
gnss-sdr Потоки GNSS-SDR Monitor і PVT-monitor у вигляді рядків JSON C/N0 за каналом, положення, використані супутники, HDOP, азимут і висота; створено integrations/gnss-sdr/relay.py

Подробиці, джерела та обмеження цих трьох: MACHINE-INPUTS.md.

Кожна епоха, яку створюють зчитувачі, також несе source_span, зсуви байтів [start, end) у вхідних даних: найменший суцільний діапазон, що містить записи, які до неї внесли, щоб точний сирий фрагмент можна було захешувати для вікна події. NMEA: кожен рядок, прочитаний, поки епоха є поточною (надмножина, якщо між її реченнями стоїть непов'язаний рядок). UBX: кадри епохи. RINEX 3: записи епохи від кожного рядка > до наступного. Android: рядки Raw епохи (рядок Fix лише для епохи без рядків Raw). Відсутній для живого потоку та всюди, де не є чітко визначеним (RINEX 2).

Файл передається через path (розв'язується відносно власної теки сценарію) або вбудовано як text чи base64 (єдині варіанти в браузері).

Журнал IMU як другий сенсор#

[log.imu] додає інерціальний журнал на тому самому годиннику:

[log.imu]
format = "csv"          # or "euroc"
path = "imu.csv"        # or text / base64
heading0_deg = 90.0     # heading at the first IMU sample
yaw_axis_down = true    # body z down (NED/FRD); false for z up (ENU/FLU)
time_offset_s = 0.0     # added to the IMU clock to reach the log's t_s

Кутова швидкість рискання інтегрується з heading0_deg і заповнює курс там, де журнал приймача його не містить, тож монітор heading-course (якому потрібне heading_sensor = true на платформі) порівнює курс за гіроскопом із курсом відносно землі. Гіроскоп дрейфує: курс настільки добрий, наскільки добре вікно інтегрування, а hdg_cog_tol_deg вирішує, що вважається розбіжністю. Розкладку csv описано в MACHINE-INPUTS.md. Байти IMU є частиною хеша сценарію та хеша сценарію пакета доказів. Вбудований текст (text/base64) працює на кожній поверхні; path відхиляється там, де файли не читаються.

Платформа: статична або судно#

Наведені вище монітори припускають нерухому антену. Сценарій заявляє платформу до прогону в таблиці верхнього рівня [platform]; без неї платформа є static і нічого не змінюється.

[platform]
kind = "vessel"            # "static" (default) or "vessel"
max_speed_kn = 30.0        # default 30
max_accel_mps2 = 0.5       # default 0.5
max_turn_rate_dps = 6.0    # default 6
antenna_height_m = 18.0    # no default: without it the sea-level monitor does not run
heading_sensor = false     # true: the stream carries a gyro heading (HDT or THS)
Ключ Типове значення Чому таке значення
max_speed_kn 30 Вище службової швидкості торговельних суден і більшості пасажирських суден, тож реальне судно її ніколи не досягає; набагато нижче за швидкість, яку передбачає зсув положення. Повільніше судно має заявити нижчу межу: чим нижча межа, тим раніше буде виявлено зсув.
max_accel_mps2 0.5 Велике судно змінює швидкість значно менш ніж на 0,1 м/с²; мала швидкісна посудина за різкої зміни газу досягає кількох десятих.
max_turn_rate_dps 6 Велике судно повертає значно менш ніж зі швидкістю 1 град/с, а мала посудина в різкому повороті — зі швидкістю кількох.
antenna_height_m немає Властивість установки; здогад був би прихованим порогом.
heading_sensor false Заявлене true і відсутнє в журналі — це помилка, тож відсутній сенсор не може пройти за чисту перевірку.

Ключі судна відхиляються за kind = "static". Для судна монітор position-jump не працює, бо він вимірює відстань від середнього калібрування, що хибно для рухомої антени; monitor_config результату фіксує платформу та використані межі.

Синтетичні потоки NMEA від kshana nmea-scenario, створені для навчання екіпажу, приймаються зчитувачем NMEA і можуть проганятися цим типом, як і будь-який журнал NMEA.

Монітори#

Кожному монітору потрібні його дані; монітор, чиїх даних немає в журналі, не запускається і не вказується в monitors_run. Перші calibration_s секунд (за замовчуванням 60) задають базовий рівень і ніколи не дають тривоги.

Монітор Тривога, коли Потребує
cn0-drop середнє C/N0 за супутниками, спільними з базовим рівнем, падає на cn0_drop_db або більше (за замовчуванням 6 дБ) C/N0
loss-of-lock відстежуваних супутників на sats_lost або більше менше за медіану базового рівня (за замовчуванням 4) C/N0
agc показник AGC відхиляється від свого базового рівня більш ніж на agc_k_sigma стандартних відхилень (за замовчуванням 5) UBX MON-RF або Android AgcDb
jam-ind jamInd u-blox перевищує jam_ind_threshold (за замовчуванням 80 із 255) UBX MON-RF
position-jump власне положення приймача віддалене від свого середнього калібрування більш ніж на position_jump_m (за замовчуванням 50 м) повідомлене положення
raim перевірка парності автономного контролю цілісності приймачем (RAIM) на власному одноточковому положенні рушія відхиляє набір вимірювань журнал RINEX із nav
solve-failure одноточкове положення рушія не розв'язується за п'яти або більше супутників журнал RINEX із nav
clock годинник приймача відхиляється від передбаченої лінії більш ніж на мінімальний виявний зсув свого шуму калібрування журнал RINEX із nav

Калібрований профіль (за бажанням). [monitors] profile = "jammertest-2024-calibrated" замінює три пороги завад значеннями, відкаліброваними на публічному наборі даних JammerTest 2024 (один u-blox ZED-F9P на сценарій; Zenodo 15911589): cn0_drop_db = 1.5, agc_k_sigma = 3.5, jam_ind_threshold = 29. Калібрування було попередньо зареєстроване (xval/jammertest-trust/PREREGISTRATION.md), а профіль має рівень MODELLED, підігнаний на одній публічній кампанії: його поріг cn0_drop_db не виконав попередньо зареєстрований поріг хибних тривог на відкладеному наборі (0,0231 проти 0,02); пороги AGC та індикатора глушіння і поріг об'єднання (хибні тривоги 0,033, виявлення 0,81) пройдено (xval/jammertest-trust/RESULTS.md). Він справджується для цього типу приймача на цій події, проти запланованих слотів атаки, і був відкалібрований на CSV-журналах набору (його журнали UBX дають більше хибних тривог у двох теках). Результат прогону з профілем повторює застосовані пороги та несе profile_note, що каже все це. Без профілю діють наведені вище значення за замовчуванням, і кожен вихід залишається незмінним.

Для платформи vessel також запускаються монітори рухомої платформи (пороги в таблиці верхнього рівня [maritime], кожне значення за замовчуванням задокументовано в src/receiver_trust/maritime.rs); кожному потрібні його дані, і він указується в monitors_run лише тоді, коли дійшов рішення:

Монітор Тривога, коли Потребує
kinematic зміна положення суперечить повідомленій швидкості й курсу або передбачає швидкість, прискорення чи кутову швидкість повороту вище меж судна положення; швидкість і курс (RMC або VTG) для частини зі зліченням шляху
heading-course курс за гіроскопом і курс відносно землі розрізняються більш ніж на hdg_cog_tol_deg (швидкість вище min_speed_kn) курс HDT, THS або VHW, heading_sensor = true
speed-log швидкість відносно води та швидкість відносно землі розрізняються більш ніж на stw_sog_tol_kn VHW або VBW і швидкість відносно землі
sea-level висота GGA відрізняється від antenna_height_m більш ніж на sea_level_tol_m висота GGA, antenna_height_m
cn0-spread розкид C/N0 між супутниками падає до cn0_spread_frac від його медіани калібрування GSV
cn0-rise C/N0 спільних супутників зросло в середньому на cn0_rise_db, і cn0_rise_frac із них зросло GSV
time-consistency послідовні часи епох змінюються нерегулярно, ідуть назад або відхиляються від годинника хоста час NMEA; годинник хоста для останньої частини
osnma приймач повідомляє про збій автентифікації OSNMA (повідомлений статус читається; нічого не перевіряється; щоб перевірити OSNMA з самих сторінок I/NAV, див. docs/OSNMA.md) речення статусу $PKSOS

Епоха є недовіреною, коли спрацьовує RAIM, монітор годинника, збій розв'язання або стрибок положення, чи падіння C/N0 досягає подвійного порога; погіршеною — за будь-якої іншої тривоги; і номінальною в іншому разі.

Шлях рушія (raim, solve-failure, clock) — це те саме обчислення, що й оракул спуфінгу JammerTest 2024 у tests/jammertest_spoof_oracle_support: tests/receiver_trust_jammertest.rs перевіряє, що на всіх вісьмох опублікованих початках перша тривога припадає на ту саму епоху і є того самого роду.

Оцінка довіри (платформа-судно)#

Для судна кожна епоха після калібрування також отримує оцінку від 0 до 100 і причини, чому вона не 100. Відображення детерміноване й зафіксоване до того, як оцінюється будь-який журнал: ніякого навчання, нічого, підігнаного під події. Кожен монітор зводить свої докази до співвідношення statistic / threshold (тривога за 1 або більше); співвідношення коштує оцінці

points = weight * clamp((ratio - onset_ratio) / (full_ratio - onset_ratio), 0, 1)
score  = round_to_0.1( clamp(100 - sum of points, 0, 100) )

тож монітор нічого не коштує, поки він нижче onset_ratio свого порога (за замовчуванням 0,5), коштує половину своєї ваги на своєму порозі та всю вагу за full_ratio порога (за замовчуванням 1,5); оцінка не зростає за жодною статистикою. Джерело, яке не звітує в епосі, зберігає свою останню статистику протягом evidence_hold_s (за замовчуванням 10 с: два цикли речення C/N0, яке надсилається кожні 5 с), і як тривогу, і як відрахування.

Округлення — до більшого за половини (floor(x * 10 + 0.5) / 10), смуга визначається за округленою оцінкою, а обмеження застосовується до округлення. У відрахуваннях перелічено лише монітори, бали яких вищі за нуль, з їхнім співвідношенням і неокругленими балами, найбільші бали першими; відрахування з рівними балами перелічено в порядку назв моніторів cn0-drop, agc, jam-ind, loss-of-lock, position-jump, raim, clock, solve-failure, kinematic, heading-course, speed-log, sea-level, cn0-spread, cn0-rise, time-consistency, osnma, geometry. Монітору, чий тест є «успіх або збій» (невдале розв'язання, невдала автентифікація), надається співвідношення 1,5, повна вага. Наведені бали — це бали до обмеження на 0.

[score]
nominal_min = 90.0         # score >= 90: nominal
degraded_min = 55.0        # 55 <= score < 90: degraded; below 55: untrusted
onset_ratio = 0.5
full_ratio = 1.5
evidence_hold_s = 10.0
[score.weights]            # overrides; a monitor not listed keeps its default
sea-level = 30.0
Вага (бали) Монітори Чому
70 osnma збій автентифікації — це констатація, а не статистика
60 kinematic, raim, clock, position-jump, time-consistency підроблене положення має суперечити фізиці або власним перевіркам приймача, а час не може йти назад; одне порушення на повну силу (1,5 порога: 60 балів, оцінка 40) є недовіреним, а на порозі (30 балів, оцінка 70) — погіршеним
40 heading-course, speed-log, solve-failure один незалежний сенсор, що розходиться, — це погіршений стан; два на повну силу — недовірений
30 sea-level, cn0-spread, cn0-rise, cn0-drop сигнальне середовище або слабко інформативна перевірка
25 loss-of-lock, agc, jam-ind середовище вороже; одне це не показує, що положення хибне
до 15, [geometry] geometry (0.36) не вага на цій шкалі: нічого, якщо небо не погане, тоді до cap_points (15); одна геометрія досягає погіршеного стану, ніколи недовіреного, і не піднімає тривоги (див. «Геометрія» нижче)

Межі смуг випливають із ваг: найлегший монітор, що дає тривогу, коштує 12,5 бала на своєму порозі, тож будь-яка тривога виводить із номінальної смуги; жоден окремий монітор нижче 60 балів не може сам досягти недовіреної смуги (кілька разом — можуть). Результат фіксує модель оцінки (score_model), а кожна епоха несе score.deductions: які монітори зробили відрахування, їхні співвідношення та їхні бали. Для судна стан епохи — це смуга її оцінки.

Геометрія: природна деградація окремо від ознак атаки#

Приймач біля причального крана, у шлюзі чи під високим корпусом втрачає супутники, і його положення погіршується з причини, що не є атакою. Починаючи з 0,36, за запискою про проєктування геометрії (docs/design/2026-10-12-geometry-and-skyline-design.md, розділ 4) кожна епоха несе свою геометрію супутників, оцінка судна має монітор геометрії, а кожне відрахування несе клас: geometry (небо), environment (сигнальне середовище) або inconsistency (докази, схожі на атаку).

Звідки береться геометрія. Висота й азимут кожного відстежуваного супутника (NMEA GSV, UBX NAV-SAT), з яких виводиться геометричний чинник DOP (погіршення точності) єдиним ядром DOP рушія (orbit::dop, VALIDATED за gnss_lib_py): source = derived. Якщо цього немає, — DOP і використані супутники, які заявляє приймач (NMEA GSA): source = reported. Положення на небі та GSA зараховуються протягом evidence_hold_s оцінки (за замовчуванням 10 с), бо багато шин надсилають GSV раз на кілька секунд; набір GSV, неповний в епосі (кінець уривка, втрачене речення), не використовується. Журнал без жодного з них, як-от NMEA лише з GGA і RMC, або журнали Android і RINEX на сьогодні, отримує статус unknown з приміткою «geometry unknown»: рушій не вгадує геометрію, якої йому не дали, а монітор геометрії не запускається.

geometry.status Значення
good достатньо супутників і DOP у межах порогів
degraded одна або кілька причин: few-satellites, high-pdop, high-hdop і (інформаційно, не входить в оцінку) sky-blocked, коли кожен відстежуваний супутник міститься в одній половині горизонту
unknown журнал не дає геометрії супутників для цієї епохи

Статус є описовим, а для оцінки має значення позначка (нижче): degraded охоплює інформаційний випадок sky-blocked, який може супроводжуватися добрим або задовільним DOP, і оцінюється лише позначка poor.

Позначка (завжди повідомляється, ніколи не оцінюється). geometry.label кожної епохи — це good (HDOP не більше hdop_good 2, PDOP не більше pdop_good 3 і щонайменше used_good 6 супутників), poor (HDOP вище hdop_max 4, PDOP вище pdop_max 6 або менше min_used 5 супутників), fair між ними, або unknown. Примітка епохи завжди починається з позначки та чисел, наприклад "geometry fair: HDOP 1,105, PDOP 1,831, VDOP 1,410, 8 satellites; not scored (the score deducts only above HDOP 4, PDOP 6 or below 5 satellites)", і додає ", signal loss", коли воно є.

Монітор геометрії (оцінка судна). Він не відраховує нічого, якщо геометрія не погана: його співвідношення — max(hdop / hdop_max, pdop / pdop_max, min_used / n_used), і поки воно не перевищує 1 (добра чи задовільна геометрія, зокрема відкрите небо лише для GPS із 8 супутників), він нічого не коштує, тож такий журнал оцінюється точно так, як у 0,35. Вище 1 відрахування лінійно зростає до cap_points (15) за full_ratio (1,5 порога: HDOP 6, PDOP 9, 3 супутники): 7,5 бала за співвідношення 1,25 (HDOP 5 або 4 супутники), 15 від 1,5 і вище (оцінка 85, погіршений стан). Сам по собі він ніколи не може опустити оцінку нижче floor (за замовчуванням: degraded_min оцінки, 55), тож одна геометрія щонайбільше досягає погіршеної смуги і ніколи недовіреної: чинне обмеження — min(cap_points, 100 - floor), тож таблиця [score], що піднімає degraded_min (наприклад, таблиця 0,35 із degraded_min 90), знижує обмеження до 100 - degraded_min, а не відхиляється, а floor, задане нижче degraded_min, відхиляється. Монітор не піднімає тривоги; він указується останнім у monitors_run, коли дійшов рішення в будь-якій епосі (судно, чий журнал дає геометрію), і не враховується в тотожності 0,35; він не є записом [score.weights] (його задання відхиляється), а чинні обмеження та нижню межу записано в geometry_model.cap_in_force і geometry_model.floor_in_force. Примітка поганої епохи каже чому, наприклад "geometry poor: HDOP 5,200, PDOP 7,900, VDOP 4,100, 7 satellites; degraded by geometry: HDOP 5,200 above 4 (derived from 7 logged satellites); not an inconsistency".

Класи. Кожне відрахування (score.deductions[].class):

Клас Монітори
geometry geometry (погана геометрія); loss-of-lock, коли кожен супутник, утрачений відносно базового рівня калібрування, був нижче low_elev_deg у своєму останньому звіті
environment cn0-drop, cn0-spread, cn0-rise, agc, jam-ind, loss-of-lock в іншому разі; geometry під час втрати сигналу (нижче)
inconsistency kinematic, heading-course, speed-log, sea-level, time-consistency, clock, raim, position-jump, osnma, solve-failure; і geometry, коли геометрія погана, а заявлений HDOP суперечить заявленому небу (нижче)

Захист від підробленого поганого неба. Спуфер може надіслати рідкий GSV або повідомити високий HDOP, щоб купити толерантність. Рушій позначає і не прощає: жодну іншу перевірку не розширює погана геометрія, а HDOP, який заявляє приймач (GSA в межах утримання, інакше GGA), порівнюється з HDOP, виведеним із заявленого ним неба. Коли вони розрізняються більш ніж на max(reported_vs_derived_tol, reported_vs_derived_rel × derived HDOP) (1,0 або 25 % виведеного HDOP, залежно від того, що більше), епоха несе reported_derived_mismatch: true, і, коли геометрія погана, її відрахування класифікується як inconsistency. За доброї чи задовільної геометрії розбіжність повідомляється і не оцінюється: нічого не відраховується, якщо геометрія не погана. Це свідомий вибір (0,36): «нуль, якщо не погано» діє для кожної епохи, тож добра й задовільна геометрія оцінюються точно так, як у 0,35, а підроблений HDOP ніколи не лишається непоміченим. Прапорець (reported_derived_mismatch) є на кожній епосі результату та кожному живому рядку, примітка каже "…beyond the tolerance: reported, not scored (the geometry is not poor)" або "…: the geometry deduction is classed an inconsistency", geometry_summary.hdop_mismatch рахує епохи, а сторінка підсумку доказів показує кількість, зокрема нуль. 25 % — це REPRESENTATIVE інженерний вибір, а не виміряне чи стандартне значення: приймач, що розв'язує один годинник на орбітальне угруповання або з підмножиною відстежуваних ним супутників (маска висоти, відсікання за C/N0, виключення RAIM), заявляє HDOP, який відрізняється від HDOP з єдиним годинником усіх відстежуваних супутників на величину, що зростає з HDOP, тож фіксований допуск сам по собі сприймав би природну погану геометрію як невідповідність. Більша різниця все одно читається як вона. Відрахування класу geometry — це твердження про небо, а не висновок, що атаки не було.

Втрата сигналу — це не небо. Коли супутники, які приймач перелічує як видимі (вище за low_elev_deg), не відстежуються, рушій також виводить DOP усіх видимих супутників. Якщо цей DOP видимих супутників у межах порогів і при цьому або нічого не відстежується, або невідстежувані супутники розподілені по всьому горизонту (не зосереджені в одній його половині), то небо було, а сигналу не було: епоха має signal_loss: true, примітку «супутники видимі, але не відстежуються: середовище сигналу, а не геометрія», а віднімання за геометрію класифіковано як environment. Невідстежувані супутники, зосереджені в одній половині горизонту, і далі розглядаються як заблоковане небо (стіна, скеля, причал). Двостороння перешкода (каньйон або вузький фіорд) розглядається як втрата сигналу, доки не налаштовано лінію горизонту. Індикатори відсутності розв'язку в приймача не є DOP: заявлений HDOP або PDOP зі значенням 99 чи більше, якість GGA 0 і режим GSA 1 не дають заявленого DOP.

ключ [geometry] Типове значення Походження
hdop_max 4 обрано (примітка до проєктування 4,2): при sigma_uere_m 1,5 м HDOP 4 дає 2drms у 12 м, тобто kin_pos_tol_m кінематичної перевірки. Стандарт IEC 61108-1 зазвичай наводять як такий, що формулює свої вимоги до точності для HDOP ≤ 4 (або PDOP ≤ 6): це пригадано з вторинної літератури про приймачі GNSS, конкретного вторинного джерела не переглядали, а сам стандарт не читали; потрібно звірити з текстом стандарту
pdop_max 6 поріг доступності за PDOP, що дорівнює scenarios/polar-arctic-leo-coverage.toml; GPS SPS Performance Standard, 5-те вид. (2020), PDOP ≤ 6, як наведено в tests/constellation_availability_published_spec_oracle.rs; потрібно звірити з текстом стандарту
min_used 5 на один більше, ніж потрібно для розв'язку, щоб одна втрата не завершувала розв'язок; найменше число з одним надлишковим вимірюванням для RAIM
sigma_uere_m 1.5 заявлений вхід для зв'язку 2drms із hdop_max; задайте власний показник приймача
reported_vs_derived_tol 1,0 HDOP обрано (примітка до проєктування 4,2): абсолютна частина допуску; розбіжність понад допуск не є геометрією
reported_vs_derived_rel 0.25 REPRESENTATIVE інженерний вибір: відносна частина, для приймачів із годинниками для кожного орбітального угруповання або з розв'язками за підмножинами
low_elev_deg 15 примітка до проєктування 4,3: супутники, втрачені нижче цього значення, втрачені через небо; лінія горизонту (0,36, пункт 1) розширить це
azimuth_gap_deg 180 геометрична, інформаційна: усі супутники в одній половині горизонту
cap_points 15 примітка до проєктування 4,2: сама лише геометрія переводить оцінку з nominal у degraded і ніколи в untrusted; віднімається лише тоді, коли геометрія погана (рішення засновника B1, 0,36)
full_ratio 1.5 власний full_ratio оцінки: рампа досягає cap_points при 1,5 поріг поганої геометрії
floor degraded_min оцінки (55) сама лише геометрія ніколи не досягає смуги untrusted; чинна межа становить min(cap_points, 100 - floor); нижня межа менша за degraded_min відхиляється
hdop_good 2 REPRESENTATIVE, лише для мітки: половина hdop_max (відношення початку для оцінки 0,35)
pdop_good 3 REPRESENTATIVE, лише для мітки: половина pdop_max
used_good 6 REPRESENTATIVE, лише для мітки: на один більше за min_used, тому одна втрата все одно залишає надлишкове вимірювання

Що змінилося у вихідних даних, а що ні. Жодна оцінка не змінюється, якщо геометрія не погана; мітка звітується завжди. Додані ключі: epochs[].geometry (status, reasons, source, n_used, hdop, pdop, vdop, округлені до 0,001, open_fraction (null, доки не налаштовано лінію горизонту), max_azimuth_gap_deg, age_s, reported_hdop, reported_derived_mismatch, note, in_view (супутники, перелічені вище за low_elev_deg), signal_loss, label), class для кожного віднімання, а в кінці geometry_model (пороги, утримання, чинні верхня й нижня межі, походження, правила класів) і geometry_summary (епохи за статусом, за міткою та за класом віднімання, а також епохи з розбіжністю із заявленим HDOP); score_model.weights — як у 0,35. Два тести звіряють це побайтово з базовою версією «0,36 portable» після вилучення цих ключів (хеші 0.35.0, перебазовані, коли рушій перейшов на портативну математику, і збережені в тестах як запис того, що випустила версія 0.35.0: docs/revisions/STUDIO15-portable-math-rebaseline.md). tests/geometry_trust_no_change.rs звіряє кожен вихід обох прикладів сеансів (JSON результату, CSV, SVG, вердикт, відтворені живі рядки, $PKSHT, Prometheus, CEF, LEEF). tests/geometry_corpus_identity.rs звіряє пакетний результат, підсумок, живі рядки та $PKSHT кожного закоміченого корпусу NMEA суден (демонстраційного й морських еталонних фікстур, кожного також як відкрите небо лише з GPS із 8 супутниками, та сценаріїв навчання екіпажів, згенерованих з їхніх зерен (seed)); у двох навчальних сценаріях, де глушіння погіршує геометрію, кожна епоха, що не погана, ідентична, а кожна погана відрізняється лише відніманням за геометрію. Журнал із поганою геометрією втрачає до 15 балів, яких не втрачав у 0,35; це задумана зміна. У демонстрації відрив читається як inconsistency; tests/geometry_trust.rs редагує журнал так, щоб замаскувати західне небо (задовільна: позначено, не оцінено), замаскувати його та два східні супутники (погана: віднімання за геометрію, втрата захоплення environment, бо високі супутники також зникли), втратити лише супутники нижче 15° (втрата захоплення geometry) і заявити HDOP, якого небо не пояснює (віднімання за погану геометрію стає inconsistency). Пороги мають рівень MODELLED: обрані, а не підігнані під жоден журнал; ніщо тут не стверджує, як часто природне погіршення й атаки розрізняються на реальних даних.

Зазначення подій і прогнозів#

[[events]]
label = "jammer on"
kind = "jamming"            # jamming, spoofing or other
onset_s = 120.0             # seconds since the first epoch of the log
end_s = 240.0               # optional; otherwise onset_s + compare.horizon_s
predicted_cn0_drop_db = 12.0  # optional, e.g. from a `jamming` scenario's link budget

[compare]
detect_tol_s = 10.0         # an alarm this soon after onset counts as a detection
cn0_tol_db = 3.0            # predicted and observed drops agree within this

Для кожної події результат дає хибні тривоги між калібруванням і початком, першу тривогу та її монітори, затримку, підсумок (detected, late, missed або not-evaluable) і спостережуване медіанне падіння C/N0 порівняно з прогнозом (agree, disagree, no-prediction або not-evaluable). Розбіжність звітується, а не підганяється: допуски задано в сценарії, а сценарій входить у хеш результату.

Чого це не стверджує#

Монітори довіри мають рівень MODELLED: їхні пороги є входами, а їхню ефективність виявлення на реальних завадах вимірює оцінювання подій, а не щось таке, що стверджує цей вид. На сеансах спуфінгу JammerTest 2024 монітори на шляху рушія ловлять деякі початки впродовж 10 с, а на інших запізнюються; числа дивіться в рядку «Clock-aided χ², RAIM, AGC, SQM fused per-epoch security FoM» у VERIFICATION-MATRIX.md. Прогноз, що збігається з одним журналом, є однією точкою даних, а не валідацією.