vi er her !!!

02120

DifferentielGPS
home

RTCM konvertering

Da vi skulle vælge en datastruktur til dekodning af RTCM signalet var der to hovedspørgsmål:
  • Hvordan laver vi repræsentationen af de binære strenge
  • Hvordan skal data for signalet opbevares

Valget af data struktur til bits

En meget væsentlig datastruktur i vores program er valget af bitsrepræsentationen. Der er ingen decideret bittype i java og boolean typen fylder 8 bits, hvilket giver 7 overflødige bits per bit. Dataen modtages, som bytes repræsenteret ved integers. Men de skal rulles og de to første overflødige "indpakningsbits" skal smides væk. Herefter skal de samles til 30 bits ord og parititesttjekkes. Efter dette tjek skal de igen skilles ad til heltat og kommatal. Derfor er det vigtigt at vælge en repræsentation af bits, som er dynamisk nok til nemt at blive konverteret.
Der er to faktorer man kan overveje, når man repræsentere bitstrenge i java. Man kan have en bitstreng som en ny klasse eller som et indbygget type. Og man kan vælge imellem, om den indbyggede type skal være et boolean array eller en integer. Da ordene er af størrelsen 30 bits kan de gemmes i 1 integer på 32 bits. Dette mindsker spildet af bits til 2. Hvis man vælger at bruge et boolean array, kommer man op på 30 booleans á 8 bits lig med 240 bits mod de 32 bits på en integer. Til gengæld er booleanværdierne nemmere at regne med. Hvis man skal bruge integer, skal man ved hvert brug udtage den bit, man skal se på. Dette giver flere udregner per sammenligning af bits og ville give parititetstjekket væsentligt flere udregninger. Således er valget af boolean det nemmeste at programmere, men måske ikke det mest optimale. Når man vælger at repræsentere bits med boolean synes en særskilt klasse til repræsentation overflødigt. Dette ville gøre koden længere, da man skulle til at lave funktionskald til at få de enkelte bits. Derfor vil en let løsning være at lade bits repræsenteres ved boolean arrays og lave statiske metoder, som kan konvertere mellem boolean arrays og integers. En programmeringteknisk smartere løsning men samtidigt tungere løsning, er at lade dem repræsentere i klasser, som indeholder integers og metoder til at udtrække dem.

Datastruktur til opbevaring

Som beskrevet i BAGGRUND REFERENCE består RTCM signalet af en række binære ord, som er samlet i beskeder (frames). Ud fra disse fås informationer om de enkelte satellitter. Vi har derfor fundet det naturligt, at have en tredeling af datastrukturen til RTCM signalet i ord, besked og satellit.

Et ord indeholder de 30 bits data og kan paritetstjekke sig selv. Oprindeligt havde vi tænkt, at ordet skulle have en information om dets nummer i rækken, så man havde en metode, som kunne hente data fra ordene. Dette viste sig dog at være et mindre egnet system, da man i så fald skulle til at overveje hvad der skulle ske, når der blev bedt om data, som ordet ikke indeholder. Vi lod derfor beskeden håndtere data. Således kan man kun bede om alt data fra ordet, eller en delmængde af den.
Da vi under dataopsamling ikke laver en hel besked, før alt data er samlet, er det nødvendigt, at ordklassen kan genkende første ord, og udtage beskedlængden af andet ord.

Beskedsklassen skal konvertere det binære data fra ordene i en fuld besked til satellitinformationer. Da vi lavede klassen til beskeder, var det oprindeligt tanken, at beskeden skulle laves af de klasser, som står for dataopsamlingen. Senere blev vi enige om, at det ikke skulle være tilfældet. Men som følge af det, har vi lavet beskedklassen, så den kan opbevare data. Hvis man kun var interesseret i, at den skulle kunne konvertere det binære data til satellit informationer, kunne man lave en klasse, som blot har én statisk offentlig tilgængelig metode til dette. Men da opbevaring var tanken, lavede vi metoder til at hente ord ud fra beskeden med mere. Da disse metoder bruges internt i klassen har vi valgt at lade dem blive.
Som nævnt under TEORI REFERENCE, må man kende den rækkefølge ordene blev modtaget i. Ud fra dette kan man finde de korrekte satellitdata. Hvis data opbevares i et array, kan beskednummeret findes ud fra indekseringen af dette. Dette har vi derfor valgt, så der ikke er behov for en eksplicit nummerering af ordene.

Satellitklassen er blot en opbevaringsklasse. Vi skal ikke i stor stil regne på dataene, men blot gemme dem og hente dem frem.

Buffere

Da det RTCM signal vi får fra gpsmodtagerne og det internetbaserede GPSNet og er det samme, er det logisk at lave en fælles læsemetode, som de forskellige enheder benytter sig af. Dette har vi valgt. Vi startede som ovennævnt med at samle dataene i ordklassen. Men da vi skulle vælge, hvordan dataene blev sendt videre i systemet, blev vi enige om at lave en buffer til den.
Denne buffer består af et array med et skrive- og et læseindeks. Når bufferen er tom er de ens, og når der tilføjes data til bufferen, skrives til den plads som skriveindekset angiver og dette forøges med 1. Man kan læse data fra læseindeksets plads og forøge læseindekset med 1. Når de to indeks atter er ens, er bufferen igen tom. Da arrays er endelige, er bufferen laves cyklisk. Når enden af arrayet nås, skrives og læses der fra starten af det igen, så fremt i fald, at bufferen ikke er fuld.
Med dette buffersystem regnede vi med, at kunne have flere beskeder liggende i samme array. Da beskedlængden kan læses fra 2. ord, behøver man ikke at have nogen variable, som angiver hvor beskedsnittet ligger. Fordelen med sådan et buffersystem er, at man kan læse og skrive fra det samtidigt. Så længde man holder øje med hvor mange beskeder der er i systemet, kan en tråd skrive til bufferen samtidig med, at en anden tråd læser. Holder man ikke øje med en hvor mange beskeder der er modtaget, vil man skulle til at læse hvert enkelt ord fra beskeden frem for en besked på en gang, hvilken så ville kræve endnu en buffer.
Det viste sig desværre, at det ikke var let at implementere systemet ordentligt. Så derfor gik vi væk fra at opbevare flere beskeder i bufferen.

Dataopsamling

Både for GPSNet og de serielle enheder gælder, at data modtages fra en InputStream.
For GPSNet kommer der kontinuerligt data ind. Det vil sige, at man kan forvente at læse fra inputsstrømmen og få svar meget kort efter.
Men for de serielle enheder gælder det, at data kommer i klumper. Den klasse, som skal læse fra en seriel enhed, skal implementere SerialPortEventListener interfacet. Hver gang der er en dataklump parat, bliver der genereret en SerialPortEvent, som man ved at implementere metoden serialEvent kan opsamle. Herefter kan man læse en begrænset mængde data fra inputstrømmen.
Det er derfor ikke hensigtsmæssigt at lave al dataopsamlingen i samme tråd. Dette ville man kunne, ved at læse én byte fra en inputsstrøm, og så, når dette er gjort, læse fra den næste inputsstrøm og så fremdeles. Dette ville dog betyde, at når blot én datastrøm er gået i stå, vil alle skulle vente på timeout fra den, hver gang der bliver forsøgt læst fra den. Desuden vil der muligvis opstå unødige ventetider, hvis en enhed sender med meget større tidsrum imellem hver dataklump end andre.
Derfor har vi valgt at delegere arbejdet ud i tråde. Alle GPSNet enheder modtager i en tråd for sig, så de ikke kommer i vejen for hinanden eller andre enheder. Serielenhederne derimod kræver kun at blive starten. Javas såkaldte Event dispatching thread tager sig af at lave en tråd og sende serial events, som modtagelsen kører i.
Ulempen ved at have flere tråde er, at man ikke ved hvornår de forskellige tråde kører. Man skal derfor undgå, at det er muligt, at to tråde skriver og læser fra samme variabel samtidigt. Dette kan ende i en såkaldt dead-lock situation, hvor begge tråde venter på at komme til at bruge samme variabel, men aldrig kommer til det. En anden ting er, at vi skal have en løkke til at samle data op, som ikke kun kører, når der er kommet nyt data. Til at starte med, havde vi lavet denne sådan, at den kørte uden pause. Men vi fandt ud af, at dette resulterede i, at den kørte mange tusinde gange uden at få noget nyt data. Den tog simpelthen alt tilgængeligt processorkraft, hvilket gjorde det umuligt at køre andre processer samtidigt med den og gjorde det svært at stoppe den igen. Derfor har vi sat denne tråd til at vente et kort tidsrum efter hver gang, den har søgt efter ny data for hver enhed.

Kort forklaring af tråde

Tråde gør, at man kan have flere processer kørende samtidigt. Det vil i vores tilfælde sige, at vi kan modtage data og skrive det til databasen uafhængigt af hinanden samtidigt og brugeren stadigvæk kan bruge GUIen mens der samles data. I Java har tråde en run metode, som indeholder den kode, som bliver udført. Når koden i run metoden er udført, stopper tråden med at køre og kan ikke genstartes. Derfor skal man sørge for, at der er en (næsten) uendelig løkke i tråden, hvis den skal køre uafbrudt. Men da man ikke kan stoppe tråden udefra, bliver man nødt til at lave en betinget uendelig løkke, som:
while(go == true)
hvor go er en boolesk variabel, som kan sætter til falsk af programmet uden for tråden.
Java og det bagvedliggende styresystem sørger for at styre hvornår trådene kører, så det ikke er programmøren, som skal side og styre det.. I princippet kan man have uendeligt mange tråde kørende samtidigt, men i praksis er det selvfølgeligt ikke realistisk på grund af begrænset computerkraft.

home