Maski horyzontu i geometria nieba
Do 0,36 każdy test widoczności Ziemi w silniku był jednym progiem elewacji, mask_deg: satelita się liczył, gdy był na tej wysokości lub powyżej niej, bez względu na kierunek. Ulica, nabrzeże, fiord lub żuraw zasłaniają część nieba, a resztę zostawiają otwartą. Skyline (horyzont) to próg elewacji zależny od azymutu; funkcje geometrii nieba zamieniają miejsce, czas, konstelacje i horyzont na zbiór widocznych satelitów, rozmycie dokładności (DOP), kowariancję geometrii, poziomą elipsę błędu, chmurę Monte Carlo i skyplot. Projekt to docs/design/2026-10-12-geometry-and-skyline-design.md (punkty 1 i 2).
Dowody: decyzja o widoczności z maską (kąty widzenia geodezyjne, maska tabelaryczna, zbiór widocznych i jego DOP) jest VALIDATED względem Orekit 12,2 i gnss_lib_py 1.0.4 w porównaniu zarejestrowanym z góry, podobnie jak elipsa błędu i kofaktor dla każdego systemu (numpy, zarejestrowane z góry); redukcje kanionu, sektora i terenu, ustawienia wstępne i pozostałe funkcje geometrii nieba są MODELLED (Dowody). Horyzont usuwa satelity w linii widzenia i nic więcej. Ustawienia wstępne to geometrie REPRESENTATIVE, a nie pomiary terenowe.
Horyzont (skyline)#
Horyzont to maksimum punktowe czterech opisów. Azymut to stopnie w prawo od północy prawdziwej w lokalnym układzie wschód-północ-góra miejsca; elewacje są w [0, 90).
| Opis | TOML | Czym jest |
|---|---|---|
| Tabela | table = [[az, el], ...] |
Elewacje interpolowane liniowo po azymucie, zawijane przy 360°. Azymuty ściśle rosnące w [0, 360); co najwyżej 3600 wierszy. |
| Kanion uliczny | street_az_deg, width_m, height_left_m, height_right_m, antenna_m, length_m |
Dwie proste równoległe ściany (poniżej). |
| Sektory | sectors = [{ az_from, az_to, el_deg }] |
Przedziały o ostrych krawędziach, w prawo od az_from (włącznie) do az_to (wyłącznie), które mogą przechodzić przez północ; co najwyżej 360. |
| Teren | terrain = [{ az, distance_m, height_m }] |
Punkty sprowadzone do tabeli: elewacja atan((height_m − d²/(2 R_eff)) / d), ze spadkiem krzywizny dla R_eff = 4/3 × 6371 km (wybrana, podana stała). height_m jest liczone nad anteną. |
preset = "<name>" zaczyna od nazwanej geometrii; pola kanionu następnie nadpisują pole kanionu ustawienia wstępnego pole po polu, a table, sectors i terrain do niego dodają.
mask_deg odbiornika zachowuje swoje znaczenie: jest to płaski horyzont. Efektywny próg przy azymucie az to max(mask_deg, skyline(az)), a satelita jest widoczny, gdy jego elewacja jest równa lub większa: to samo >=, którego zawsze używała płaska maska. Satelita powyżej mask_deg, lecz poniżej horyzontu, jest zasłonięty przez horyzont.
Kanion uliczny#
Ulica biegnie wzdłuż azymutu s, w metrów między ścianami, antena a metrów nad ziemią na osi. Wzdłuż azymutu az, przy θ = az − s, promień dociera do ściany po d(az) = (w/2) / |sin θ|, więc ściana o wysokości h tnie przy
cut(az) = atan( (h − a) / d(az) ) (the right wall for sin θ > 0, the side at s + 90°)
Otwarty pas leży wzdłuż ulicy. Przy length_m = L (antena pośrodku) promień wychodzi przez otwarty koniec, a ściana nic nie zasłania, gdy d(az) · |cos θ| > L/2. Ściana nie wyższa niż antena nic nie zasłania. antenna_m domyślnie wynosi 1,5 m (dach samochodu lub odbiornik ręczny, wybór podany wprost); nowy kanion wymaga width_m.
Gotowe ustawienia#
Wybrane i podane wymiary (z noty projektowej), a nie pomiary żadnego rzeczywistego miejsca. kshana skyline --preset <name> wypisuje jedno z nich z jego pochodzeniem i jego progiem co stopień.
| Ustawienie predefiniowane | Geometria | Pochodzenie |
|---|---|---|
city-street |
Kanion: ulica 0°, szerokość 20 m, ściany 30 m i 30 m, antena 1,5 m. 70,7° w poprzek ulicy, otwarty wzdłuż niej. | Stosunek wysokości do szerokości 1,5, w paśmie 0,5–2 proporcji kanionów ulicznych według Oke (1988), Street design and urban canopy layer climate, Energy and Buildings 11, 103–113. |
harbour-approach |
Sektory: otwarte w stronę morza na 090–270 (180°); budynki nabrzeża 8° na 315–045 (90°); falochron i jego światło 3° na 045–090 i 270–315. | Wybory podane wprost (na przykład magazyny 40 m w odległości około 285 m). |
fjord |
Teren: ściany 600 m nad anteną w odległości 1500 m po obu stronach kanału północ-południe, jeden punkt na stopień (przy 1500/|sin az| m), z uwzględnionym spadkiem krzywizny. 21,8° w poprzek, poniżej 1° wzdłuż osi. |
Rząd wielkości szerokości i deniwelacji głębokich fiordów zachodniej Norwegii (Holtedahl (1967), Notes on the formation of fjords and fjord-valleys, Geografiska Annaler 49A, 193–203). |
container-terminal |
Sektory: stosy kontenerów 12° na lądowej połowie 000–180; wysięgniki żurawi 35° na 245–255 i 25° na 285–295; poza tym otwarte w stronę wody. | Pięć kontenerów high-cube ISO 668 (14,5 m) w odległości około 60 m od anteny na wysokości 2 m; wysięgnik około 50 m nad nabrzeżem na 70 m i 100 m, rzędu żurawia post-Panamax. Sektor żurawia jest nieprzezroczysty. |
W scenariuszu#
Opcjonalna sekcja [skyline], nad własnym progiem danego rodzaju:
| Rodzaj | Co zmienia horyzont | Dla każdej próbki |
|---|---|---|
orbit (z user_site) |
Oś czasu widoczności (dostępność GNSS) i podsumowanie DOP. | — |
integrity (z user_site) |
Satelity, z których korzystają RAIM i ARAIM (araim_dual). |
epochs[].masked_by_skyline |
gnss-sim |
Satelity, których pseudoodległości są symulowane i używane przez RAIM. | gnss_measurements[].masked_by_skyline |
jamming |
Satelity, które odbiornik może śledzić, przed zagłuszaczem. | epochs[].masked_by_skyline |
leo-pvt |
Zbiór widocznych satelitów każdego trybu nad maską własną każdego systemu, w tym przemiatanie biegunowe (ten sam horyzont w każdym miejscu). Obwiednia trybu Dopplera i zaprojektowany pojedynczy przelot to granice tego, co odbiornik musi obsłużyć, i zachowują maskę każdego systemu. | joint.epochs[].masked_by_skyline |
leo-pass |
Które epoki liczą się jako powyżej maski, czas powyżej niej, satelity porównania GNSS. | satellites[].pass.epochs_masked_by_skyline |
nmea-scenario (szkoleniowe NMEA) |
Satelity w GSV i w rozwiązaniu. Azymuty to rzeczywiste kierunki związane z ziemią, a nie kurs statku. | — |
Miejsce naziemne dla orbit i integrity. Oba rodzaje modelują orbitującego użytkownika z elewacją geocentryczną i bez azymutu związanego z Ziemią, więc przyjmują horyzont tylko w trybie miejsca naziemnego z noty projektowej: user_site = { lat_deg, lon_deg, height_m } zamiast user (dokładnie jedno z dwóch). Każda próbka to jedna bezwzględna chwila, epoch + t: każdy satelita jest do niej propagowany (zestaw elementów, efemeryda rozgłaszana lub plik SP3 jest przesuwany od własnej epoki, satelita Walker liczy t od epoch) i obracany do układu związanego z Ziemią w tej chwili, więc miejsce widzi jedno spójne niebo. epoch jest własną epoką scenariusza orbity; bez niej (i zawsze dla integrity, który jej nie ma) jest to najnowsza epoka wśród satelitów, które ją niosą, lub J2000 tylko dla wzorców Walker. Elewacja i azymut są geodezyjne (WGS-84). Podział poziomów ochrony ARAIM na poziomy i pionowy rodzaju integrity oraz błędu pionowego Stanforda używa tej samej geodezyjnej pionowej (normalnej do elipsoidy WGS-84, około 0,19° od radialnej geocentrycznej na szerokości 45°); migawkowy RAIM już jej używał. user_site bez horyzontu to zwykły użytkownik naziemny; ścieżka orbitującego user jest bez zmian.
kind = "integrity"
mask_deg = 5.0
# ...
[user_site]
lat_deg = 59.45
lon_deg = 24.75
height_m = 15.0
[skyline]
preset = "harbour-approach"
Kompatybilność wsteczna. Bez sekcji [skyline] scenariusz jest identyczny bajt po bajcie z tym, co ten sam silnik dawał, zanim istniał kod horyzontu: tests/skyline_scenarios.rs sprawdza JSON, wykres i podsumowanie każdego dostarczanego scenariusza, który uruchamia jeden z tych rodzajów, oraz tekst NMEA każdego scenariusza szkoleniowego, względem skrótów SHA-256 punktu odniesienia „0,36 portable” (skrótów z commitu wydania 0.35.0, przeliczonych ponownie, gdy silnik przeszedł na matematykę przenośną, i zachowanych w teście jako zapis: docs/revisions/STUDIO15-portable-math-rebaseline.md). Pusta sekcja [skyline] nic nie zasłania; wynik jest wtedy równy przebiegowi bez niej, z wyjątkiem dodanego bloku skyline i zerowych liczników masked_by_skyline.
Co jest odrzucane, z powodem w komunikacie: horyzont na orbitującym user; user i user_site razem; nieznane ustawienie wstępne; kanion bez width_m; tabela, która nie jest ściśle rosnąca w [0, 360); elewacja poza [0, 90); pusty sektor; niedodatnia odległość terenu; dane wejściowe ponad limitami; dowolny nieznany klucz.
Wynik zyskuje skyline: { source, open_fraction, provenance }, gdy sekcja jest obecna: source to preset:<name>, preset:<name>+overrides lub custom; open_fraction to ułamek kąta bryłowego górnej półkuli powyżej max(mask_deg, skyline) (średnia z 1 − sin(cut) po azymucie: 1 dla zerowej maski, 0,5 dla płaskiego progu 30°); provenance to wiersz ustawienia wstępnego lub własny wiersz scenariusza. Jednostki i klasy pochodzenia znajdują się w bloku units.
Dołączone przykłady (kshana example <name>):
| Przykład | Co pokazuje (usuń sekcję [skyline], aby porównać) |
|---|---|
orbit-urban-canyon-skyline |
GPS + Galileo na dole city-street: 17 z 289 próbek zachowuje rozwiązanie, mediana PDOP 70,5 (1,14 przy otwartym niebie). |
integrity-harbour-approach |
ARAIM dla dwóch konstelacji przy wejściu do portu: 70 ukrytych epok satelitów, dostępność bez zmian (145 z 145). |
gnss-sim-container-terminal-skyline |
Pseudoodległości i RAIM na nabrzeżu: 44 ukryte epoki satelitów; dostępność RAIM 0,59 (0,85 przy otwartym niebie). |
jamming-harbour-approach-skyline |
Zagłuszacz 2 W w porcie: 83 ukrytych epok satelitów, śledzenie bez zmian (zagłuszacz już je odebrał). |
leo-pvt-fjord-skyline |
GPS + Galileo + warstwa LEO w fiordzie: mediana połączonego PDOP 1,14 (0,93 przy otwartym niebie). |
leo-vertical-autonomous-vehicle-skyline |
Kanion leo-vertical-autonomous-vehicle jako płaski próg 35° i jako city-street obrócony wzdłuż kursu samochodu: 8 wobec 4 do 5 satelitów GPS i Galileo; połączony średni błąd 2,1 m w obu przypadkach; alarm 1,5 m w 51 % i 59 % epok. |
Geometria nieba#
Pięć funkcji silnika (src/geometry.rs), takich samych na każdej powierzchni:
| Funkcja | Wejście → wyjście |
|---|---|
sky_geometry(request) |
dla każdego satelity id, system, az_deg, el_deg, cut_deg, visible, masked; n_visible, n_masked, open_fraction; dop (GDOP, PDOP, HDOP, VDOP, TDOP, tdop_by_clock); states, cofactor_enu (wariancja jednostkowa), covariance_enu_m2; ellipse_1sigma i ellipse przy żądanym poziomie ufności; label, statement, advisory |
sky_monte_carlo(request, seed, n) |
n (co najwyżej 5000, limit wejściowy) błędów metody najmniejszych kwadratów przy niezależnych gaussowskich błędach zasięgu σ_UERE ze strumienia ChaCha8 z ziarnem (seed) seed: samples_enu_m, empiryczna kowariancja, poziome i 3-D RMS obok σ_UERE × HDOP i σ_UERE × PDOP, ułamek wewnątrz elipsy 95 % |
skyline_presets() |
ustawienia wstępne z etykietą, opisem, pochodzeniem, progiem co stopień i open_fraction |
skyline_profile(skyline) |
sekcja horyzontu sprowadzona do 360-wpisowej tabeli używanej przez silnik, z source, provenance, open_fraction |
skyplot_svg(request) |
skyplot jako statyczny SVG (bez skryptu, bez odwołań zewnętrznych, każdy ciąg wejściowy z escapowaniem) |
Żądanie:
{
"site": {"lat_deg": 59.91, "lon_deg": 10.75, "height_m": 5},
"time_s": 3600,
"systems": ["gps-baseline", "galileo", "beidou-meo", "xona-pulsar"],
"mask_deg": 5,
"skyline": {"preset": "fjord"},
"clock": "per-system",
"sigma_uere_m": 1.5,
"confidence": 0.95
}
systems to ustawienia wstępne konstelacji silnika (constellation-design: gps-baseline, galileo, beidou-meo, glonass, ...; ustawienia wstępne LEO xona-pulsar, iridium-stl, ...) lub pełna tabela leo-pvt [[system]], propagowane do time_s (keplerowskie z wiekowym J2, orbity trybu łączonego leo-pvt). Ich względne fazy pochodzą z różnych epok odniesienia, więc niebo to reprezentatywna geometria, a nie niebo z tej daty w tym miejscu. Satelity można zamiast tego (lub dodatkowo) podać bezpośrednio: "satellites": [{"id": "G05", "system": "GPS", "az_deg": 120, "el_deg": 35}, ...], lub z "ecef_m": [x, y, z] i site albo user_ecef_m. Wartości domyślne: maska własna każdego systemu (5° GNSS, 10° LEO; 5° dla satelitów podanych bezpośrednio), jeden zegar odbiornika na system ("common" dla jednego wspólnego zegara), σ_UERE 1 m (reprezentatywna linia budżetu dwuczęstotliwościowego), poziom ufności 0,95. Limity wejściowe: co najwyżej 2000 satelitów nad horyzontem (tabela systemu żądająca więcej jest odrzucana przed zbudowaniem) i 16 zegarów odbiornika.
Datowane niebo z zestawów elementów. "tle" przyjmuje tekst zestawów elementów dwuwierszowych (wiersz z nazwą przed każdym zestawem jest opcjonalny; co najwyżej 4 MiB, limit wejściowy), propagowany przez SGP4 silnika (WGS-72, propagator, którego używa orbit-real-tle) do "epoch" plus time_s, obrócony do układu związanego z Ziemią przy UT1 przyjętym jako UTC i bez ruchu bieguna, i widziany z site. "epoch" to UTC ISO 8601 (2026-06-07T12:00:00Z) i datuje tylko zestawy elementów (ustawienia wstępne nie mają daty, więc epoch bez tle jest odrzucane); "tle_system" oznacza je dla zegara każdego systemu (domyślnie TLE). Każdy wynik podaje, jakie to niebo, w sky_source i sky_statement:
sky_source |
Niebo |
|---|---|
presets |
ustawienia wstępne konstelacji silnika: reprezentatywna geometria |
tle-at-epoch |
zestawy elementów propagowane do podanej epoki: niebo, które te zestawy dają w tej epoce, a nie jego pomiar (ich własna dokładność to dokładność SGP4 i wiek zestawów) |
tle-at-element-epoch |
brak epoch: zestawy elementów propagowane do własnej epoki najnowszego zestawu plus time_s, reprezentatywne niebo |
satellites |
satelity podane bezpośrednio, tak jak podano |
Mieszankę łączy się za pomocą +. epoch_utc to chwila, do której propagowano zestawy elementów, a tle_skipped wymienia, jakiej części tekstu nie użyto, wraz z powodem: źle sformułowane lub osierocone wiersze zestawów elementów (z numerami wierszy), zestawy odrzucone przez parser i zestawy, których SGP4 nie mógł propagować do tej chwili (rozpadłe lub poza swoimi granicami); co najwyżej 100 wpisów łącznie, a potem jeden ostatni wpis liczący resztę. Pusta lista systems nie dodaje żadnych ustawień wstępnych. Skyplot podaje podstawę w stopce.
Jedno jądro. Macierz kofaktorów to orbit::cofactor_from_los, czyli złożenie macierzy projektu i odwrotność Gaussa-Jordana stojące za orbit::dop. orbit::dop_cov udostępnia kowariancję, a orbit::dop jest jej redukcją, więc skalary VALIDATED pozostają bez zmian i są nadal przypięte przez tests/dop_reference.rs. Nie ma drugiej implementacji DOP.
Elipsa. Półosie k σ √λ dla wartości własnych λ bloku wschód-północ, z k = √(−2 ln(1 − p)) (√5.991 = 2.448 przy 95 %, 1 przy 39,35 %) oraz azymut osi wielkiej ½ atan2(2 Q_EN, Q_NN − Q_EE) w [0, 180) od północy.
| Powierzchnia | Punkty wejścia |
|---|---|
| CLI | kshana sky <request.json|toml> lub kshana sky --site <lat,lon[,h]> (--systems <a,b> | --tle <file>) [--epoch] [--tle-system] [--time] [--mask] [--skyline-preset] [--uere] [--clock], z --monte-carlo <n> --seed <s> lub --svg; kshana skyline --preset <name> | --presets | --profile <file> |
| Rust | kshana::geometry::{sky_geometry, sky_monte_carlo, skyline_presets, skyline_profile, skyplot_svg}, kshana::surface::* o tych samych nazwach |
| Python | kshana.sky_geometry, sky_monte_carlo, skyline_presets, skyline_profile, skyplot_svg |
| WASM | sky_geometry(request_json), sky_monte_carlo(request_json, seed, n), skyline_presets(), skyline_profile(skyline_json), skyplot_svg(request_json) |
| MCP | sky_geometry (request lub skyline_preset); bez Monte Carlo przez MCP (masowe próbki, które agent powinien streszczać, a nie nosić) |
Każdy wynik zawiera label (MODELLED), statement (geometria przy podanym modelu błędu: niezależne, równe, o zerowej średniej gaussowskie błędy zasięgu; nie jest to prognoza rzeczywistego błędu odbiornika, który ma też biasy, wielodrogowość i błędy spoza linii widzenia; nie jest to granica integralności) oraz uwagę doradczą: Oprogramowanie wyłącznie doradcze, nie jest to sprzęt nawigacyjny z zatwierdzeniem typu (IEC 61108, IEC 61162): za nawigację statku odpowiada nadal operator.
Dowody#
Pięć wierszy rejestru (docs/VERIFICATION-MATRIX.md), tak jak zakresuje je nota projektowa:
| Wiersz | Status | Wyrocznia |
|---|---|---|
| Maska horyzontu zależna od azymutu: zbiór widocznych satelitów, azymut i elewacja oraz DOP przy masce | VALIDATED | Orekit 12,2 (kąty widzenia TopocentricFrame, ElevationMask) z gnss_lib_py 1.0.4 (get_dop i macierz DOP), zarejestrowane z góry w xval/orekit-skyline/PREREGISTRATION.md (commit e4b9d912), zanim uruchomiono którekolwiek: 1173 kątów widzenia w sześciu miejscach i czterech epokach, sześć tabel, 142 zbiorów widocznych; najgorsza elewacja 1.3e-13°, azymut 2.3e-13°, maska 1.1e-12° wobec 1e-9°; identyczne zbiory widocznych, żaden w paśmie granicznym; DOP 3.3e-13 względnie i kofaktor 6.6e-13 skali macierzy wobec 1e-9. Zakres: maski tabelaryczne, kąty widzenia geodezyjne, zbiór zasłonięty oraz jego DOP ze wspólnym zegarem i kofaktor. |
| Redukcje kanionu ulicznego, sektorów i terenu do tabeli | MODELLED | wartości obliczone ręcznie; powyższe porównanie czyta ich tabele jako dane wejściowe i ich nie sprawdza |
| Wstępne ustawienia skyline | MODELLED | brak: wybrane, jawnie podane wymiary (sprawdzane wyłącznie względem siebie) |
| Elipsa błędu poziomego i kofaktor dla poszczególnych systemów z kowariancji geometrii | VALIDATED | numpy 2.5.4 linalg.inv i linalg.eigh (standard P2) na 142 zatwierdzonych widocznych zbiorach, przy wspólnym zegarze i jednym zegarze na system, wstępnie zarejestrowane w xval/numpy-ellipse/PREREGISTRATION.md (commit 0bbeeaee): 270 przypadków, osie 5.1e-13 względnie, orientacja 5.3e-12°, kofaktor 1.0e-12 skali macierzy, wobec 1e-9 i 1e-6° |
| Funkcje geometrii nieba | MODELLED | kompozycja: propagacja ustawień wstępnych do reprezentatywnego nieba, chmura Monte Carlo (sprawdzana względem geometrii, którą próbkuje), powierzchnie |
Brak sekcji [skyline] jest sprawdzany bajt po bajcie względem wyników z wersji 0.35.0, co pokazuje zgodność wsteczną i niczego nie potwierdza niezależnym wzorcem. gnss_lib_py stosuje wyłącznie jedną maskę elewacji, więc jest tu wyrocznią dla DOP, a nie dla maski.
Czego skyline nie modeluje: dyfrakcji na krawędzi ściany, odbić i sygnałów bez bezpośredniej widoczności, które rzeczywisty odbiornik może nadal śledzić (są odrzucane, a nie osłabiane), częściowej przezroczystości (żuraw kratownicowy jest nieprzezroczysty w całym swoim sektorze), terenu poza podanymi punktami oraz krzywizny Ziemi wewnątrz form kanionu i sektora.