Siste oppdatering
Python-kode som les inn bin-filer
Under er eit døme på å lese inn filer av det binære .bin-formatet som er brukt for separasjonsmodellane mellom referansenivå i kystsona og til havs, publisert av Kartverket. Dette er same format som er brukt for høgdereferansemodellane for NN2000 og NN1954.
# -*- coding: utf-8 -*- ''' Under er eit døme på å lese inn filer av det binære .bin-formatet som er brukt for separasjonsmodellane mellom referansenivå i kystsona og til havs, publisert av Kartverket. Dette er same format som er brukt for høgdereferansemodellane for NN2000 og NN1954. Det er definert ein funksjon for å lese inn filene til ein dictionary, deretter vert funksjonen brukt for å lese inn fila "ChartDatum_above_Ellipsoid_EUREF89_v2021a.bin", og resultatet plotta. I koden under er det antatt at den .bin-fila ligg i same mappe som skriptet. Lisensiert under Creative Commons BY-SA 3.0 https://creativecommons.org/licenses/by-sa/3.0/ ''' import struct import numpy as np import matplotlib.pyplot as plt def readbinfile(filename): '''Returnerer dictionary med data frå .bin-fil. Parametre --------- filename : string Filnamn eller fullstendig sti til .bin-fil som skal lesast inn Returnerer ---------- D : dictionary Oppføringer i dict er - lat : Nx1 numpy array med breiddegradsverdier - lon : Mx1 numpy array med lengdegradsverdier - data : NxM numpy masked array med modellverdiar - dlon : avstand mellom gridpunkt i aust-vest-retning - dlat : avstand mellom gridpunkt i nord-sør-retning - ellipsoide : viss UTM-koordinatar, gjev aktuell ellipsoide - UTM-sone : viss UTM-koordinatar, gjev UTM-sonen Notat ----- Formatet i .bin-filene som HREF og separasjonsmodellane kjem i er eit Gravsoft-binærformat. Verdiane er på eit regulært grid, med radene langs linjer av breiddegrad, og kolonnene langs linjer av lengdegrad. Fila er delt i blokker på 64 byte, den fyrste blokken inneheld metadata. Resten av fila er modellverdiar som "single precision" flyttal, det vil seie 4 byte for kvart tal. Alle tal i same 64 byte-blokk er på same breiddegrad, og verdiane går frå vest mot aust. Fyrste rad er den nordlegaste. Det vil seie, den fyrste verdien er i det nordvestre hjørnet, den siste i det søraustre hjørnet. Innhald i metadata-blokken, fyrste 64 byte: - Byte 1-4: Icode - 4 byte integer, variabel som skal ha verdi 777. Viss ikkje er det feil med big/little endian. - Byte 5-12: Rnmin - 8 byte float/double, gir minste breiddegrad for grid - Byte 13-20: Rnmax - 8 byte float/double, gir største breiddegrad for grid - Byte 21-28: Remin - 8 byte float/double, gir minste lengdegrad for grid - Byte 29-36: Remin - 8 byte float/double, gir største lengdegrad for grid - Byte 37-44: deltaN - 8 byte float/double, gir gridstørrelse i breiddegradsretning - Byte 45-52: deltaE - 8 byte float/double, gir gridstørrelse i lengdegradsretning - Byte 53-56: Iutm - 4 byte integer. Viss geografisk grid lik 0 - Byte 57-60: Iell - 4 byte integer. Lik 0 for geografisk grid. For UTM-grid, kode for å definere ellipsoide. - Byte 61-64: Izone - 4 byte integer. Angir UTM-sone, viss geografisk grid er den lik 0. Griddet i fila vil då ha N = (Rnmax - Rnmin)/deltaN + 1 rader og M = (Remax - Remin)/deltaE + 1 kolonner. OBS: viss M ikkje går opp i 16 i talet på verdiar i kvar blokk, vil slutten av den siste blokken på ei rad vere fylt med null. T.d. om M = 2801, vil det vere mod(2801, 16) = 1 reelle datapunkt i den siste blokken på ei rad, og dermed får ein 16 - 1 = 15 nullverdiar på slutten av kvar rad. Metode for lesing tatt frå https://stackoverflow.com/a/8711061 ''' # les inn heile fila gitt ved stien with open(filename, mode='rb') as file: fileContent = file.read() # pakk ut fyrste fire byte til int, og sjekk om lik 777 Icode = struct.unpack('i', fileContent[:4]) if Icode[0] != 777: raise('Icode er ikkje 777, feil endian') # pakk ut neste 48 byte som double precision floats Rnmin, Rnmax, Remin, Remax, dn, de = struct.unpack('dddddd', fileContent[4:4+8*6]) # pakk ut siste del av metadatablokk som tre ints Iutm, Iell, Izone = struct.unpack('iii', fileContent[4+8*6:64]) # dict med ellipsoider ellipsoids = { 0: 'LatLon', 1: 'WGS84/NAD83', 2: 'Hayford/ED50', 3: 'Clarke/NAD27', } modEll = ellipsoids[Iell] if Iell in ellipsoids.keys() else 'Undefined' # har ikkje testa med UTM-grid, so gi ut advarsel viss det er tilfelle if Iutm != 0: Warning('UTM-koordinatar i fil -- veit ikkje om dette fungerer') # pakk ut resten av fila som single precision float, og legg i numpy array data = struct.unpack('f' * ((len(fileContent) - 64) // 4), fileContent[64:]) data = np.array(data) # rekn ut storleik på grid Nlon = round((Remax-Remin)/de) + 1 Nlat = round((Rnmax-Rnmin)/dn) + 1 # lag dict med lat/lon vektorar og anna metadata # merk lat-vektoren går frå nord til sør for å samsvare med data-matrisa D = {'lat': np.linspace(Rnmax, Rnmin, Nlat), 'lon': np.linspace(Remin, Remax, Nlon), 'dlat': dn, 'dlon': de, 'ellipsoide': modEll, 'UTM-sone': Izone} N = data.size if (N / Nlat) % 1 != 0: raise('Talet på datapunkt går ikkje opp i talet med breiddegradpunkt.') # kor mange datapunkt det er per rad, inkludert nullar Nlon_with_zeros = N//Nlat # (differansen mellom matrisestørrelse med og utan null-verdiar) delt på # (differansen mellom radstørrelser med og utan null-verdiar) # burde verte lik talet på rader if (N - Nlon*Nlat) / (Nlon_with_zeros - Nlon) != Nlat: raise('Feil tal på datapunkt i forhold til lat-lon-griddet.') # reshape data til array, og fjern nullverdiane på slutten av kvar rad data = data.reshape((int(Nlat), int(Nlon_with_zeros)))[:, :Nlon] # lag masked_array og legg til i dict # maske basert på størrelsen til verdiane D['data'] = np.ma.masked_array(data, mask=np.abs(data) > 500) return D # definer namn på fila som skal lesast inn, og bruk funksjonen over filnamn = 'ChartDatum_above_Ellipsoid_EUREF89_v2021a.bin' modeldata = readbinfile(filnamn) # lag matriser med lengde- og breiddegradsverdiar lon, lat = np.meshgrid(modeldata['lon'], modeldata['lat']) # plott resultatet fig, ax = plt.subplots() g = ax.pcolormesh(lon, lat, modeldata['data']) ax.set_xlabel('Lengdegrad') ax.set_ylabel('Breiddegrad') ax.set_title('Sjøkartnull over ellipsoiden') cb = fig.colorbar(g) cb.set_label('Meter') plt.show()
Separasjonsmodeller
Kartverket tilbyr ein rekke separasjonsmodellar som gjev deg skilnaden mellom to ulike referansenivå eller høgdesystem for eit geografisk område.
Desse kan ta deg frå GNSS-målingar til høgder over havet eller over sjøkartnull, eller frå djupnedata i sjøkart til høgder i NN2000.
E-posten er sendt