Довіра до приймача: оцінювання реального журналу приймача GNSS
kshana receiver-trust читає журнал реального приймача глобальної навігаційної супутникової системи (GNSS), проганяє над ним монітори довіри епоха за епохою та каже, коли і чому визначення положення приймачем перестало бути надійним. Він також може оцінити журнал за подіями та прогнозами, які ви заявляєте до прогону: чи було кожну подію виявлено вчасно і чи змодельоване падіння відношення потужності несівної до густини шуму (C/N0) узгоджується з тим, що виміряв приймач.
Спостережувані величини — власні для приймача; монітори та їхні пороги належать рушієві й вам. Кожен результат несе цю позначку, SHA-256 журналу та кожен поріг, з яким працював, тож прогін можна повторити й перевірити.
Для судна на ходу, з живою оцінкою та необов'язковим шлюзом перед системою карт див. MARITIME-TRUST.md.
Запуск#
kshana receiver-trust examples/receiver-trust/session.toml
Це записує session.result.json, session.trust.csv (один рядок на епоху) і session.trust.svg (середнє C/N0 за часом зі станом довіри під ним) поруч зі сценарієм і друкує однорядковий вердикт. Приклад журналу є синтетичним, створеним, щоб показати формат; націльте path на журнал власного приймача.
Наведена вище діаграма — демонстрація судна з 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. Прогноз, що збігається з одним журналом, є однією точкою даних, а не валідацією.