Op 21 oktober 1978 vertrok de 20-jarige Frederick Valentich1 met zijn Cessna 1822 vanop de luchthaven van Kingeiland3 (Australië). Ongeveer 45 minuten na het opstijgen maakte hij radiocontact met de luchtverkeersleiding in Melbourne om te melden dat er zich een groot vliegtuig met vier lichten op ongeveer dezelfde hoogte bevond.

Frederick Valentich
De onverklaarde verdwijning van de Australische piloot Frederick Valentich in 1978.

Hij zei dat het gevaarte met zeer hoge snelheid op ongeveer 1.000 voet (300 m) boven hem was gepasseerd. Hij beschreef het als "een lange vorm" met "een groen licht" en zei dat het "metaalachtig" was, alsof het "overal blonk". Daarna zei hij nog

Het lijkt alsof hij een soort spelletje met mij wil spelen. Hij vliegt twee … drie keer over mij aan snelheden die ik niet kan inschatten.

Even later meldde hij dat het object "verdwenen" was en daarna zei hij dat het terug naderde vanuit het zuidwesten. Een paar minuten later zei hij

Melbourne, dat vreemde vliegtuig hangt weer boven me. … Het is aan het zweven en het is geen vliegtuig.

De microfoon van Valentich's radio bleef daarna nog 17 seconden openstaan en in die tijdspanne hoorde luchtverkeersleider Steve Robey "metaalachtige schurende geluiden" voordat het signaal wegstierf. Er werd nooit nog een spoor van Valentich of zijn vliegtuig teruggevonden.

Opgave

De OpenSky Network API4 is een RESTful5 web service6 waarmee live informatie over het luchtruim kan opgevraagd worden voor onderzoek en niet-commerciële doeleinden. De URL

https://opensky-network.org/api/states/all7

geeft een lijst van zogenaamde State Vectors8 terug in JSON formaat. Elke State Vector beschrijft de toestand van een vliegtuig (voornamelijk positie, snelheid en identiteit) op een bepaald tijdstip. We hebben dit JSON-formaat reeds omgezet naar een tekstbestand waarvan elke regel 17 velden met informatie over een vliegtuig bevat. De velden worden telkens van elkaar gescheiden door een puntkomma (;) en bevatten zelf geen puntkomma's. Zo'n tekstbestand ziet er dan bijvoorbeeld als volgt uit (airplanes.txt9):

71c293;AAR761;Republic of Korea;1544531618;1544531619;116.9663;7.2267;12192;false;247.77;215.11;0;null;12969.24;7141;false;0
ab4e94;AAL83;United States;1544531618;1544531618;-159.5829;17.6578;10972.8;false;240.14;203.21;0.33;null;11643.36;2420;false;0
4bab47;THY4BD;Turkey;1544531619;1544531619;31.7443;41.6225;11582.4;false;215.48;256.33;0;null;11369.04;1304;false;0
424317;AFL1156;United Kingdom;1544531619;1544531619;41.061;49.8635;10675.62;false;221.43;156.59;0;null;10485.12;1564;false;0
46d0ae;;Greece;1544531615;1544531615;24.1268;38.0463;2720.34;false;90.2;57.58;9.75;null;2712.72;7447;false;0
e40087;FAB6051;Brazil;1544531547;1544531556;-45.9886;-23.0904;1135.38;false;108.23;299;0.33;null;1242.06;2467;false;0
896513;FDB1KF;United Arab Emirates;1544531619;1544531619;22.9365;47.1051;11277.6;false;244.46;139.44;0;null;10965.18;6553;false;0
4691c1;AEE3BR;Greece;1544531620;1544531620;17.2443;41.3157;11285.22;false;256.7;137.52;0;null;11109.96;0117;false;0
4400b3;AUA796;Austria;1544531619;1544531619;19.2778;46.4904;10370.82;false;224.53;316.58;0;null;9997.44;4550;false;0
440080;EZY3093;Austria;1544531619;1544531619;18.3759;46.2867;10668;false;240.3;132.57;0.65;null;10347.96;4742;false;0
…

De handleiding van de OpenSky Network API bevat de volgende omschrijvingen van de 17 informatievelden.

index property type description
0 icao24 string Unique ICAO 24-bit address of the transponder in hex string representation.
1 callsign string Callsign of the vehicle (8 chars). Can be null if no callsign has been received.
2 origin_country string Country name inferred from the ICAO 24-bit address.
3 time_position int Unix timestamp (seconds) for the last position update. Can be null if no position report was received by OpenSky within the past 15s.
4 last_contact int Unix timestamp (seconds) for the last update in general. This field is updated for any new, valid message received from the transponder.
5 longitude float WGS-84 longitude in decimal degrees. Can be null.
6 latitude float WGS-84 latitude in decimal degrees. Can be null.
7 baro_altitude float Barometric altitude in meters. Can be null.
8 on_ground boolean Boolean value which indicates if the position was retrieved from a surface position report.
9 velocity float Velocity over ground in m/s. Can be null.
10 true_track float True track in decimal degrees clockwise from north (north=0°). Can be null.
11 vertical_rate float Vertical rate in m/s. A positive value indicates that the airplane is climbing, a negative value indicates that it descends. Can be null.
12 sensors int[] IDs of the receivers which contributed to this state vector. Is null if no filtering for sensor was used in the request.
13 geo_altitude float Geometric altitude in meters. Can be null.
14 squawk string The transponder code aka Squawk. Can be null.
15 spi boolean Whether flight status indicates special purpose indicator.
16 position_source int Origin of this state’s position: 0 = ADS-B, 1 = ASTERIX, 2 = MLAT

Schrijf een bash shell script airplanes dat kan gebruikt worden om een overzicht te maken van de vliegtuigen in het luchtruim die zich het dichtst bij een gegeven punt op Aarde bevinden. Punten op Aarde worden voorgesteld aan de hand van hun coördinaten $$(\lambda, \varphi)$$, waarbij $$\lambda \in \mathbb{R}$$ de lengtegraad en $$\varphi \in \mathbb{R}$$ de breedtegraad van het punt voorstelt. De grootcirkelafstand $$d$$ tussen twee punten $$(\lambda_1, \varphi_1)$$ en $$(\lambda_2, \varphi_2)$$ op een bol met straal $$r = 6371\mbox{ km}$$ (de gemiddelde straal van de Aarde) wordt dan gegeven door de formule \[d = r \cdot \arccos(\sin(\varphi_1) \cdot \sin(\varphi_2) + \cos(\varphi_1)\cdot \cos(\varphi_2) \cdot \cos(\lambda_1 - \lambda_2))\]

grootcirkelafstand

Om de grootcirkelafstand te berekenen van alle vliegtuigen in een tekstbestand met State Vectors airplanes.txt10 tot een punt met gegeven coördinaten $$(\lambda, \varphi)$$ kan je gebruikmaken van het commando distance. Aan dit commando moeten twee argumenten $$\lambda, \varphi \in \mathbb{R}$$ doorgegeven worden. Het commando leest het tekstbestand met State Vectors uit stdin en schrijft het terug uit naar stdout, waarbij er achteraan een extra kolom wordt toegevoegd met de grootcirkelafstand (in kilometer, afgerond tot het dichtsbijzijnde natuurlijk getal) van het vliegtuig tot het punt met de gegeven coördinaten $$(\lambda, \varphi)$$.

$ cat airplanes.txt11 | distance 40.7128 -74.006
71c293;AAR761;Republic of Korea;…;false;0;18229
ab4e94;AAL83;United States;…;false;0;9384
4bab47;THY4BD;Turkey;…;false;0;11759
424317;AFL1156;United Kingdom;…;false;0;12813
e40087;FAB6051;Brazil;…;false;0;4349
896513;FDB1KF;United Arab Emirates;…;false;0;10790
4691c1;AEE3BR;Greece;…;false;0;10147
4400b3;AUA796;Austria;…;false;0;10381
440080;EZY3093;Austria;…;false;0;10280
461f63;FIN4KX;Finland;…;false;0;10377
…

Het shell script airplanes mag ervan uitgaan dat het commando distance12 in dezelfde directory staat, maar mag er niet van uitgaan dat die directory voorkomt in het zoekpad van de bash shell.

Aan het shell script airplanes moeten verplicht twee argumenten $$\lambda$$ en $$\varphi$$ doorgegeven worden die de coördinaat van een punt op Aarde voorstellen. Optioneel kan als derde argument ook nog de locatie van een tekstbestand doorgegeven worden met de State Vectors van vliegtuigen in het luchtruim. Als er geen derde argument wordt doorgegeven dan moet het shell script de State Vectors uitlezen van stdin. Bij het omzetten van het JSON-formaat naar het formaat waarbij de informatievelden worden gescheiden door puntkomma's, hebben we ook alle State Vectors weggelaten waarbij informatie ontbreekt (null) die nodig is voor deze opgave (de informatievelden callsign, origin_country, longitude en latitude). Het shell script mag er dus van uitgaan dat er geen ontbrekende informatie is.

Het shell script airplanes moet een overzicht uitschrijven van de vliegtuigen uit het gegeven tekstbestand die zich het dichtst bij het gegeven punt op Aarde bevinden. Elk vliegtuig staat in het overzicht op een afzonderlijke regel die het kenteken (callsign) bevat, gevolgd door een dubbelpunt (:), een spatie, de grootcirkelafstand van het vliegtuig tot het gegeven punt op Aarde (in kilometer, afgerond tot het dichtsbijzijnde natuurlijk getal), nog een spatie en de tekst km. De vliegtuigen moeten in het overzicht opgelijst worden volgens stijgende grootcirkelafstand tot het gegeven punt (afgerond) en daarna alfabetisch op kenteken.

Het shell script airplanes moet ook de volgende opties ondersteunen, waarbij aan de opties -n en -d verplicht een integer-argument moet meegegeven worden:

Het shell script moet voor de verwerking van de opties de flexibiliteit aan de dag leggen die gebruikelijk is bij Unix commando's: volgorde van opties speelt geen rol, opties kunnen eventueel samengenomen worden, gebruik van -- om opties en argumenten van elkaar te scheiden, …. Het shell script moet ook de volgende foutafhandeling voorzien:

Als er zich geen fouten voordoen dan moet het shell script eindigen met exit status 0.

Voorbeeld

Onderstaande voorbeeldsessie geeft aan hoe het shell script airplanes moet kunnen gebruikt worden. Hierbij gaan we ervan uit dat het tekstbestand airplanes.txt13 zich in de huidige directory bevindt.

$ airplanes 40.7128 -74.006 airplanes.txt
AIJ2995: 18 km
ASA1420: 30 km
UAL384: 212 km
FDY1052: 294 km
JBU1068: 557 km
SWA2170: 700 km
JBU1017: 742 km
FFT1693: 823 km
JBU52: 862 km
AAL466: 995 km
...
$ airplanes -n5 40.7128 -74.006 < airplanes.txt
AIJ2995: 18 km
ASA1420: 30 km
UAL384: 212 km
FDY1052: 294 km
JBU1068: 557 km
$ airplanes -d500 40.7128 -74.006 < airplanes.txt
AIJ2995: 18 km
ASA1420: 30 km
UAL384: 212 km
FDY1052: 294 km
$ airplanes -cn6 -d1000 40.7128 -74.006 < airplanes.txt
AIJ2995 (Mexico): 18 km
ASA1420 (United States): 30 km
UAL384 (United States): 212 km
FDY1052 (United States): 294 km
JBU1068 (United States): 557 km
SWA2170 (United States): 700 km
$ airplanes -cn6 -d1000 40.7128 -74.006 < airplanes.txt
AIJ2995 (Mexico): 18 km
ASA1420 (United States): 30 km
UAL384 (United States): 212 km
FDY1052 (United States): 294 km
JBU1068 (United States): 557 km
SWA2170 (United States): 700 km
$ airplanes 40.7128 < airplanes.txt
Syntaxis: airplanes [-n <integer>] [-d <integer>] [-c] longitude latitude [file]
$ echo $?
1
$ airplanes 40.7128 -666.006 < airplanes.txt
airplanes: invalid coordinates
$ echo $?
2
$ airplanes 40.7128 -74.006 unknown
airplanes: cannot access 'unknown'
$ echo $?
3

Epiloog: OK, de tweede grootste dan …

Muhammad Ali14 werd ooit door een stewardess gevraagd of hij zijn veiligheidsgordel wilde vastmaken. Ali antwoordde:

Superman heeft geen veiligheidsgordel nodig.

De stewardess gaf hem de volgende repliek:

Superman heeft ook geen vliegtuig nodig.
Frederick Valentich
Unknown Origins & Untimely Ends: A Collection of Unsolved Mysteries (Emy Bitner, 2013).