Fully support the conversion of RINEX 2.xx & RINEX 3.xx

This commit is contained in:
KenanZhu111 committed 2024-11-17 15:16:42 +08:00
1 parent 3bf4f85363
commit 357010c137
6 files changed
+478 -257

No files matched your search

+403 -186
View File
@@ -1,19 +1,28 @@
# @ File : rnx_convert.py
# @ File : rnx_convert.py
#
# @ Brief : RINEX Convert functions.
#
# Copyright (c) 2024 - 2024 KenanZhu. All Right Reserved.
#
# @ Author : KenanZhu
# @ Time : 2024/11/13
# @ Brief :
# @ Time stamp : [2024/11/13] First release.
# : [2024/11/14] Correct: convert of observation type of
# 'P1/P2' of GPS is correct into 'C1W/C2W'.
# : [2024/11/15] Fix bug: remove the empty observation of
# RINEX 2.xx format.
# : [2024/11/17] Add new: complish the funtions of convert
# form RINEX 3.xx to RINEX 2.xx and also support
# convert in major version of RINEX.
# :
# @ IDE : PyCharm
# @ IDE/Editor : PyCharm / VisualStudio Code
#
# ----------------------------------------------------------------------------------------
# ---STDPORT--- #
import re
import time
import math
import threading
# ------------- #
emp=''
bnk=' '
@@ -21,9 +30,9 @@ bnk=' '
def conv_time():
# generate convert timestamp
covpro='KNZ_Convert ver1.2.5'
covtmp='COV-PGM / DATE'
covcom='COMMENT'
# Get the locate time and transform to RINEX format
# Get the locate time and transform to Uni-format
y=time.localtime().tm_year
m=time.localtime().tm_mon
d=time.localtime().tm_mday
@@ -41,14 +50,12 @@ def conv_time():
outline=(covpro +
20*bnk +
localtime+
covtmp +
covcom +
'\n')
return outline
# Convert Format ------------------------------ #
# Convert data format --------------------------- #
def datefmt2_conv(inline):
hou=inline[49:51]
min=inline[52:54]
@@ -60,9 +67,7 @@ def datefmt2_conv(inline):
bnk + "UTC" +
bnk + "PGM / RUN BY / DATE\n")
# Convert Format ------------------------------ #
# Convert data format --------------------------- #
def datefmt3_conv(inline):
hou=inline[49:51]
min=inline[51:53]
@@ -70,17 +75,15 @@ def datefmt3_conv(inline):
return (inline[0:49] +
hou + ':' +
min + ':' +
sec + ':' +
sec +
'UTCPGM / RUN BY / DATE\n')
# Convert observ type of RINEX 2.xx to Uni-Format --------------- #
# Convert observ type of RINEX 2.xx to Uni-format ------------- #
def obsfmt2_conv(obstypes, sys):
counter =0
obstypex=[]
obsbomit=''
obsbomit=emp
match sys:
case 'G':
@@ -144,9 +147,7 @@ def obsfmt2_conv(obstypes, sys):
return obstypex
# Convert observ msg of RINEX 2.xx to Uni-Format ---------------- #
# Convert observ msg of RINEX 2.xx to Uni-format ---------------- #
def obstype2_conv(inline, in_f, omilist):
# uni-format message label
obsobs='SYS / # / OBS TYPES'
@@ -182,14 +183,12 @@ def obstype2_conv(inline, in_f, omilist):
outline=7*bnk
return outlines
# Convert obstpe msg of RINEX 2.xx to Uni-Format --------------- #
def obstpe2_conv(inline, outlines, desver):
# Generate the convert stamp ------------------------ #
def conv_stamp(inline, outlines, desver):
oriver=inline[ 5: 9]
# generate convert stamp
obscov='COV-OBSERVATION DATA'
covpro='COV-RINEX VER / TYPE'
obscom='COMMENT'
outlines.append( 5*bnk+
oriver+
@@ -198,16 +197,14 @@ def obstpe2_conv(inline, outlines, desver):
1*bnk+
obscov+
24*bnk+
covpro+
obscom+
'\n')
outlines.append(conv_time())
outlines.append(
inline.replace('%s'%re.search(r'[1-9]\d*.\d*|0\.\d*[1-9]\d*', inline).group(), desver))
return
# Convert head_data of RINEX 2.xx to Uni-format -------------- #
# Convert RINEX 2.xx(header) to Uni-format -------------- #
def rnx2_head2uni(in_f, desver, outlines, omilist):
# rinex message label
obscom='COMMENT'
@@ -221,11 +218,11 @@ def rnx2_head2uni(in_f, desver, outlines, omilist):
while True:
inline=in_f.readline()
# file is aleady checked so no need to judge again
if not inline: pass
if not inline: break
if inline.find(obscom)>=0: outlines.append(inline)
elif inline.find(obspro)>=0: outlines.append(datefmt2_conv(inline))
elif inline.find(obsobs)>=0: outlines.extend(obstype2_conv(inline, in_f, omilist))
elif inline.find(obstpe)>=0: obstpe2_conv(inline, outlines, desver)
elif inline.find(obstpe)>=0: conv_stamp(inline, outlines, desver)
elif inline.find(obsl12)>=0: continue
elif inline.find(obsend)>=0: break
else : outlines.append(inline)
@@ -235,9 +232,7 @@ def rnx2_head2uni(in_f, desver, outlines, omilist):
return 1
# Convert obs of RINEX 2.xx to Uni-Format ------------------- #
# Convert RINEX 2.xx(data) to Uni-Format ------------------- #
def rnx2_data2uni(in_f, outlines, omilist, obsnum):
sPRN=[]
scounter=0
@@ -245,7 +240,7 @@ def rnx2_data2uni(in_f, outlines, omilist, obsnum):
# return false when file end
inline=in_f.readline()
if not inline : return False
if not inline: return False
# get epoch message & flag state
year = int(inline[0 :3])
@@ -310,17 +305,13 @@ def rnx2_data2uni(in_f, outlines, omilist, obsnum):
outlines.append(sPRN[i]+outline+"\n")
return True
# Convert Uni-format to RINEX 3.xx --------------------- #
def uni2rnx3_data(outlines, out_path):
out_f = open(out_path, 'a')
out_f=open(out_path, 'a')
out_f.writelines(outlines)
out_f.close()
return
# Get observ type need be omitted --------------------- #
def getomit(omilist):
for i in range(len(omilist)):
@@ -333,36 +324,391 @@ def getomit(omilist):
omilist.pop(0)
return
# Convert data of RINEX 2.xx to Des-format ----------------- #
# Convert RINEX 2.xx to Des-format --------------------- #
def rnx2des(in_path, out_path, oriver, desver):
headread=False
outlines=[]
omilist=[]
# convert rinex 2.xx(header) to Uni-format
# convert RINEX 2.xx(header) to Uni-format
in_f=open(in_path, 'r')
match rnx2_head2uni(in_f, desver, outlines, omilist):
case 1: headread=True
case 0: headread=False
uni2rnx3_data(outlines, out_path)
outlines=[]
if headread:
if headread:
# convert Uni-foramt(header) to Des-format
match desver[0:1]:
case '2': addemp=uni2rnx2_data(4, outlines, out_path, True, None)
case '3': uni2rnx3_data(outlines, out_path)
outlines=[]
# get each observ type and omit the empty
obsnum=omilist[0]
omilist.pop(0)
getomit(omilist)
# convert RINEX 2.xx(data) to Uni-format
while rnx2_data2uni(in_f, outlines, omilist, obsnum):
# convert Uni-foramt(data) to Des-format
match desver[0:1]:
case '2': return 0
case '2': uni2rnx2_data(4, outlines, out_path, False, addemp)
case '3': uni2rnx3_data(outlines, out_path)
outlines=[]
elif not headread: return 0
in_f.close()
return 1
# Get the position of new add observ type ----------------- #
def getaddemp(alltypes, sysstype):
addemp=[[],[],[],[]]
for i in range(len(sysstype)):
for j in range(len(sysstype[i])):
for k in range(len(alltypes)):
if sysstype[i][j]==alltypes[k]:
addemp[i].append(k)
return addemp
# Filter the same obs fmt in RINEX 2.xx ----------------- #
def obsfmt_filter(alltypes):
empemp=[]
spos=npos=0
empemp.append(len(alltypes))
while True:
npos+=1
if spos==empemp[0]: break
if npos==empemp[0]:
spos+=1
npos=spos
continue
if not alltypes[spos]: continue
if not alltypes[npos]: continue
if alltypes[spos]==alltypes[npos]:
alltypes[npos]=emp
empemp.append(npos)
# restruct the data
totnum=empemp[0]
empemp=sorted(empemp[1:])
empemp.insert(0,totnum)
empemp.clear()
# addemp.append(empemp)
# clear the empty
alltypes=[obs for obs in alltypes if obs!=emp]
return alltypes
# Sort by observ type --------------------------- #
def sort_observ(alltypes):
alltypex=[]
temtypes=[]
freindex=['1','2','3','4',
'5','6','7','8']
obsetype=['C','L','D','S']
for type in alltypes:
freidx=freindex.index(type[1:2])/ 1
if type=='P1C' or type=='P2C':
tyeidx=obsetype.index(type[2:3])/10
else:
tyeidx=obsetype.index(type[0:1])/10
alltypex.append(freidx+tyeidx)
sdx=ndx=0
while True:
if len(alltypex)==0:
break
if (ndx+1)==len(alltypex):
temtypes.append(alltypes[sdx])
alltypes.pop(sdx)
alltypex.pop(sdx)
sdx=ndx=0
continue
ndx+=1
if alltypex[ndx]<=alltypex[sdx]:
sdx=ndx
continue
return temtypes
# Convert observ type of RINEX 3.xx to Uni-Format --------------- #
def obsfmt3_conv(alltypes):
alltypex=[]
for type in alltypes:
if type[1:2]=='1':
if type=='C1W': type='P1'
elif type[1:2]=='2':
if type=='C2W': type='P2'
else: pass
alltypex.append(type[0:2])
return alltypex
# Convert observ msg of RINEX 3.xx to Uni-Format ---------------- #
def obstype3_conv(i, sysnum, outlines, outlinex):
sysstype=[]
alltypes=[]
obstypes=[]
# rinex message label
obsobs='# / TYPES OF OBSERV'
for j in range(sysnum):
obstypes=[]
# reject system not support in Uni-Format
match outlines[i][0:1]:
case 'G': obstypes.append(0)
case 'E': obstypes.append(1)
case 'R': obstypes.append(2)
case 'S': obstypes.append(3)
case _:
i+=1
continue
obsnum=int(outlines[i][1:6])
for k in range(math.ceil(obsnum/13)):
obstypes.extend(outlines[i][6:60].split())
if k+1==math.ceil(obsnum/13): break
i+=1
# check the differ observ type in glonass
if obstypes[0]==2:
try:
pos=obstypes.index('C1P')
obstypes[pos]='P1C'
except ValueError: pass
try:
pos=obstypes.index('C2P')
obstypes[pos]='P2C'
except ValueError: pass
sysstype.append(obsfmt3_conv(obstypes[1:]))
alltypes=list(set(obstypes[1:]+alltypes))
i+=1
# sort observ types
alltypes=sort_observ(alltypes)
# convert observ type into des-format
alltypes=obsfmt3_conv(alltypes)
# fliter the same observ type
alltypes=obsfmt_filter(alltypes)
# get new added pos
addemp=getaddemp(alltypes, sysstype)
num =len(alltypes)
outline=4*bnk+'%2d'%num
for j in range(num):
outline+=4*bnk+alltypes[j]
if (j+1)==num:
bnx=((9-num%9)*6)*bnk
outlinex.append(outline+bnx+obsobs+'\n')
outline=0*bnk
elif (j+1)%9==0:
bnx=0*bnk
outlinex.append(outline+bnx+obsobs+'\n')
outline=6*bnk
# get amout of observ tyeps
addemp.append(num)
return addemp
# Get the total amount of sat system -------------------- #
def getsys_rnx3(in_f):
# rinex message label
obsobs='SYS / # / OBS TYPES'
readst=False
syslis=[]
sysnum=0
while True:
inline=in_f.readline()
if not inline: break
if inline.find(obsobs)>=0:
readst=True
sys=inline[0:1]
if sys and sys not in syslis:
syslis.append(sys)
sysnum+=1
elif readst and inline.find(obsobs)<0: break
in_f.seek(0)
return sysnum
# Convert head_data of RINEX 3.xx to Uni-format -------------- #
def rnx3_head2uni(in_f, desver, outlines):
# rinex message label
# obscom='COMMENT'
obstpe='RINEX VERSION / TYPE'
# obspro='PGM / RUN BY / DATE'
# obsobs='SYS / # / OBS TYPES'
obsshi='SYS / PHASE SHIFT'
obsrsb='GLONASS COD/PHS/BIS'
obsrsl='GLONASS SLOT / FRQ #'
obsend='END OF HEADER'
# get input head file & convert
while True:
inline=in_f.readline()
# file is aleady checked so no need to judge again
if not inline: break
#if inline.find(obscom)>=0: outlines.append(inline)
#elif inline.find(obspro)>=0: outlines.append(inline)
#elif inline.find(obsobs)>=0: outlines.append(inline)
elif inline.find(obstpe)>=0: conv_stamp(inline, outlines, desver)
elif inline.find(obsshi)>=0: continue
elif inline.find(obsrsb)>=0: continue
elif inline.find(obsrsl)>=0: continue
elif inline.find(obsend)>=0: break
else : outlines.append(inline)
# get the end message after break
outlines.append(60*bnk+obsend+'\n')
return 1
# Convert obs of RINEX 3.xx to Uni-format ------------------- #
def rnx2uni3_data(outlines, in_f):
inline=in_f.readline()
if not inline: return False
if not int(inline[30:32])==0: return True
outlines.append(inline)
satnum=int(inline[33:35])
for i in range(satnum):
outlines.append(in_f.readline())
return True
# Convert RINEX 3.xx(epoch msg) to RINEX 2.xx --------------- #
def rnx3rnx2_epo(outline, sPRN):
outlines=[]
datedat=outline.split()
outline=(
'%3d%3d%3d%3d%3d%11.7f%3d%3d'
%(int(datedat[1])-2000,int(datedat[2]), int(datedat[3]),# |year |month |day
int(datedat[4]) ,int(datedat[5]),float(datedat[6]),# |hour |minute |second
int(datedat[7]) ,len(sPRN))) # |flag |satnum |
# convert to RINEX 2.xx
satnum=len(sPRN)
for i in range(satnum):
outline+=sPRN[i]
if (i+1)==len(sPRN):
outlines.append(outline+'\n')
elif (i+1)%12==0:
outlines.append(outline+'\n')
outline=32*bnk
return outlines
# Convert RINEX 3.xx(data of each sat) to RINEX 2.xx ------------ #
def rnx3rnx2_dat(addemp, obsnum, outline):
outlines=[]
num=range(len(addemp))
empdat=16*bnk
outlinx=[empdat for i in range(obsnum)]
for i,j in zip(num,addemp):
if not outlinx[j]==empdat: continue
if outline[i*16+3:i*16+16+3]:
outlinx[j]=outline[i*16+3:i*16+16+3]\
.replace('\n',2*bnk).replace('\r',2*bnk)
else: continue
outline=emp
for i in range(len(outlinx)):
outline+=outlinx[i]
for i in range(math.ceil(len(outline)/80)):
outlines.append(outline[i*80:i*80+80]+'\n')
return outlines
# Convert RINEX 3.xx to RINEX 2.xx --------------------- #
def rnx3rnx2_data(outlines, addemp):
sPRN=[]
datline=[]
outlinex=[]
# filter the sat system ecxcept:#
# ---GPS-Galileo-GLONASS-SBAS---#
for i in range(len(outlines)):
if outlines[i][0:1]=='G': pass
elif outlines[i][0:1]=='E': pass
elif outlines[i][0:1]=='R': pass
elif outlines[i][0:1]=='S': pass
else: continue
datline.append(i)
sPRN.append(outlines[i][0:3])
outlinex.extend(rnx3rnx2_epo(outlines[0], sPRN))
for i in datline:
if outlines[i][0:1]=='G': idx=0
elif outlines[i][0:1]=='E': idx=1
elif outlines[i][0:1]=='R': idx=2
elif outlines[i][0:1]=='S': idx=3
else: continue
outlinex.extend(rnx3rnx2_dat(addemp[idx], addemp[4], outlines[i]))
return outlinex
# Convert Uni-format to RINEX 2.xx --------------------- #
def uni2rnx2_data(sysnum, outlines, out_path, headordata, add_emp):
# rinex message label
obspro='PGM / RUN BY / DATE'
obsobs='SYS / # / OBS TYPES'
obsend='END OF HEADER'
outlinex=[]
obsread=False
# convert Uni-format to RINEX 2.xx(header)
if headordata:
for i in range(len(outlines)):
if outlines[i].find(obspro)>=0: outlinex.append(datefmt3_conv(outlines[i]))
elif outlines[i].find(obsobs)>=0:
if not obsread:
obsread=True
addemp=obstype3_conv(i, sysnum, outlines, outlinex)
else: continue
elif outlines[i].find(obsend)>=0: outlinex.append(outlines[i])
else: outlinex.append(outlines[i])
# convert Uni-format to RINEX 2.xx(data)
elif not headordata:
outlinex=rnx3rnx2_data(outlines, add_emp)
# output to destination file
out_f=open(out_path, 'a')
out_f.writelines(outlinex)
out_f.close()
if headordata: return addemp
elif not headordata: return 0
# Convert data of RINEX 3.xx to Des-format ----------------- #
def rnx3des(in_path, out_path, oriver, desver):
headread=False
outlines=[]
in_f=open(in_path, 'r')
# get the amount of sat system
sysnum=getsys_rnx3(in_f)
# convert RINEX 3.xx(header) to Uni-format
match rnx3_head2uni(in_f, desver, outlines):
case 1: headread=True
case 0: headread=False
# convert Uni-foramt(header) to Des-format
if headread:
match desver[0:1]:
case '2': addemp=uni2rnx2_data(sysnum, outlines, out_path, True, None)
case '3': uni2rnx3_data(outlines, out_path)
outlines=[]
# convert RINEX 3.xx(data) to Uni-format
while rnx2uni3_data(outlines, in_f):
# convert Uni-foramt(data) to Des-format
match desver[0:1]:
case '2': uni2rnx2_data(sysnum, outlines, out_path, False, addemp)
case '3': uni2rnx3_data(outlines, out_path)
outlines=[]
elif not headread: return 0
return 1
# Reject data of invaild input ----------------------- #
def rnx_reject(in_path, out_path, oriver):
@@ -393,8 +739,6 @@ def rnx_reject(in_path, out_path, oriver):
return 1
# ---------------------------------------------------------------------------------------
# CONVERT FUNCTION
#
@@ -413,12 +757,11 @@ def Convert_Un(in_path, out_path, oriver, desver, resqueue):
if file_state:
match oriver:
case '2': rnx2des(in_path, out_path, oriver, desver)
case '3': resqueue.put(0)
else : resqueue.put(0)
resqueue.put(1)
return
case '3': rnx3des(in_path, out_path, oriver, desver)
else : return resqueue.put(0)
return resqueue.put(1)
# Multi-threading task --------------------------- #
def _Convert_Un(in_path, out_path, oriver, desver, resqueue):
T=threading.Thread(
@@ -426,130 +769,4 @@ def _Convert_Un(in_path, out_path, oriver, desver, resqueue):
)
T.start()
T.join()
return resqueue.get()
# --------------------------------------------------------------- #
# The functions below are not be useable. on progress............ #
#
#
# --------------------------------------------------------------- #
# Convert observ type of RINEX 3.xx to Uni-Format --------------- #
def obsfmt_conv_cxx(obstypes):
outlines=[]
outline='%6d'%len(obstypes)
for i in range(len(obstypes)):
outline+='%6s'%obstypes[i]
if (i+1)==len(obstypes):
outlines.append(outline + (9 - (i+1)%9)*6*bnk + '# / TYPES OF OBSERV\n')
outline=''
elif (i+1)%9==0:
outlines.append(outline + '# / TYPES OF OBSERV\n')
outline=6*bnk
return outlines
# Convert observ msg of RINEX 3.xx to Uni-Format ---------------- #
def obstype_conv_cxx(obstypes, inline, in_f):
while True:
if inline[0:1]=='G': flag=True
elif inline[0:1]=='E': flag=True
elif inline[0:1]=='R': flag=True
elif inline[0:1]=='S': flag=True
else: flag=False
if flag:
obsnum=int(inline[2:6])
for i in range(math.ceil(obsnum/13)):
for obs in inline[6:60].split():
if obs[1:2]=='3': continue
if obs[1:2]=='4': continue
if obs[2:3]=='P': obs='P'+obs[1:2]
else: obs=obs[0:2]
if obs and obs not in obstypes:
obstypes.append(obs)
if i+1==math.ceil(obsnum/13):
break
inline=in_f.readline()
return
# Convert head_data of RINEX 3.xx to Uni-format -------------- #
def rnx3_head2uni(in_path, out_path, desver):
try:
with open(in_path, 'r'): pass
except FileNotFoundError:
return -12
obstypes=[]
outlines=[]
in_put=False
output=False
in_f=open(in_path, 'r')
while True:
inline=in_f.readline()
if not inline:
return 0
if in_put and not output:
if not inline.find('SYS / # / OBS TYPES')>=0:
output=True
if in_put and output:
outlines.extend(obsfmt_conv_cxx(obstypes))
in_put=False
output=False
if inline.find('COMMENT')>=0:
outlines.append(inline)
elif inline.find('RINEX VERSION / TYPE')>=0:
if not inline.find('OBSERVATION DATA')>=0:
return -10
if not float(inline[5: 9])>=3:
return -10
# Output convert message
outlines.append(
5*bnk+'%s->%s'%(str(inline[5: 9]),str(desver))+
1*bnk+'COV-OBSERVATION DATA'+
24*bnk+'COV-RINEX VER / TYPE\n')
outlines.append(conv_time())
outlines.append(inline.replace(
'%s'%re.search(r'[1-9]\d*.\d*|0\.\d*[1-9]\d*', inline).group(),
desver))
elif inline.find('PGM / RUN BY / DATE')>=0:
outlines.append(datefmt3_conv(inline))
elif inline.find('SYS / # / OBS TYPES')>=0:
in_put=True
obstype_conv_cxx(obstypes, inline, in_f)
elif inline.find('SYS / PHASE SHIFT')>=0:
continue
elif inline.find('GLONASS COD/PHS/BIS')>=0:
continue
elif inline.find('GLONASS SLOT / FRQ #')>=0:
continue
elif inline.find("END OF HEADER")>=0:
outlines.append(inline)
break
else: outlines.append(inline)
try:
with open(out_path, 'w'): pass
except PermissionError:
return -11
out_f=open(out_path, 'a')
out_f.writelines(outlines)
out_f.close()
return 1
return resqueue.get()