0


【Python】伪距单点定位

一、算法原理

1.关于伪距单点定位

GPS伪距单点定位的原理比较简单,主要是利用空间距离的后方交会,用一台接收机同时接受四颗卫星的位置坐标和卫星与接收机的距离,运用后方交会原理解算出接收机的三维坐标。其中,如果接收机观测的卫星的数目多于四颗,则采用最小二乘法进行平差计算,求解出接收机坐标。

2.伪距单点定位的具体原理

(1)伪距观测方程

若得到了测站的近似坐标,则可以使用泰勒展开得到线性化方程如下。

(2)列写伪距观测方程,线性化后,得到误差方程:

(3)计算信号发射时刻卫星i的位置与信号到达时接收机的近似距离之间的距离。

3.伪距单点定位程序的计算步骤

1.读取RINEX N文件,将所有星历放置到一个列表ephlst(数组)中。

2.读取RINEX O文件,读取一个历元观测值epoch。

3.数据预处理

根据数组中的卫星号和历元时刻T在ephlst查找相应的卫星星历,

准则

4.程序初始化,设置测站概略位置为Xr,接受机钟差dtr。

14.输出该历元定位结果

二、程序设计

1.读取文件及数据准备

  1. # 数据处理
  2. import numpy
  3. def donfile(path):
  4. with open(path, 'r') as f:
  5. # 获取行数
  6. lines_n = f.readlines()
  7. Ndata = []
  8. # 获取数据组数
  9. data_line_num = int(len(lines_n) / 8)
  10. print(data_line_num)
  11. Ndataitemkeys = ['IODE', 'Crs', 'Delta_n', 'M0', 'Cuc', 'e', 'Cus', 'sqrt_A', 'TEO', 'Cic', 'OMEGA_A0', 'Cis', 'i0',
  12. 'Crc',
  13. 'omega', 'OMEGA_DOT', 'IDOT', 'L2Codes', 'GPSWEEK', 'L2PCODE', '卫星精度', '卫星健康状态', 'TGD', 'IODC',
  14. '电文发送时刻', '拟合区间', '备用1', '备用2']
  15. # 遍历
  16. for i in range(data_line_num):
  17. Ndataitem = {}
  18. k = 0
  19. for j in range(8):
  20. data_countent = lines_n[8 * i + j]
  21. Ndataitem['数据组号'] = i + 1
  22. if j == 0:
  23. Ndataitem['卫星PRN号'] = data_countent.strip('\n')[0:3]
  24. Ndataitem['历元'] = data_countent.strip('\n')[4:23]
  25. I = data_countent.strip('\n')[23:42] # [:-4]+ 'e' + data_countent.strip('\n')[24:42][-3:]
  26. Ndataitem['卫星钟差参数s'] = str(float(
  27. (data_countent.strip('\n')[23:42][:-4].strip()) + 'e' + data_countent.strip('\n')[23:42][-3:]))
  28. Ndataitem['卫星钟漂参数s/s'] = str(float(data_countent.strip('\n')[42:61][:-4].strip()) * numpy.power(10.0, -int( data_countent.strip( '\n')[42:61][-2:])))
  29. Ndataitem['卫星钟漂速度参数s/s/s'] = str( float(data_countent.strip('\n')[61:80][:-4].strip()) * numpy.power(10.0,int(data_countent.strip('\n')[62:80][-2:])))
  30. IB = data_countent.strip('\n')[2:22][-4] # 1-1.731250000000
  31. elif 0 < j < 7:
  32. if data_countent.strip('\n')[4:23][-3] == '-':
  33. Ndataitem[Ndataitemkeys[k]] = str(
  34. float(data_countent.strip('\n')[4:23][:-4].strip()) * numpy.power(10.0, -int(
  35. data_countent.strip('\n')[4:23][-2:])))
  36. else:
  37. Ndataitem[Ndataitemkeys[k]] = str(
  38. float(data_countent.strip('\n')[4:23][:-4].strip()) * numpy.power(10.0,
  39. int(data_countent.strip('\n')[
  40. 4:23][-2:])))
  41. if data_countent.strip('\n')[23:42][-3] == '-':
  42. Ndataitem[Ndataitemkeys[k + 1]] = str(
  43. float(data_countent.strip('\n')[23:42][:-4].strip()) * numpy.power(10.0, -int(
  44. data_countent.strip('\n')[23:42][-2:])))
  45. # IB = data_countent.strip('\n')[2:22][-4] # 1-1.731250000000
  46. else:
  47. B = data_countent.strip('\n')[23:42][:-4]
  48. Ndataitem[Ndataitemkeys[k + 1]] = str(
  49. float(data_countent.strip('\n')[23:42][:-4].strip()) * numpy.power(10.0, int(data_countent.strip('\n')[23:42][-2:])))
  50. if data_countent.strip('\n')[42:61][-3] == '-':
  51. Ndataitem[Ndataitemkeys[k + 2]] = str(float(data_countent.strip('\n')[42:61][:-4].strip()) * numpy.power(10.0, -int(data_countent.strip('\n')[42:61][-2:])))
  52. else:
  53. Ndataitem[Ndataitemkeys[k + 2]] = str(
  54. float(data_countent.strip('\n')[42:61][:-4].strip()) * numpy.power(10.0,int(data_countent.strip( '\n')[42:61][-2:])))
  55. if data_countent.strip('\n')[61:80][-3] == '-':
  56. Ndataitem[Ndataitemkeys[k + 3]] = str(float(data_countent.strip('\n')[61:80][:-4].strip()) * numpy.power(10.0, -int(data_countent.strip('\n')[61:80][-2:])))
  57. else:
  58. Ndataitem[Ndataitemkeys[k + 3]] = str( float(data_countent.strip('\n')[61:80][:-4].strip()) * numpy.power(10.0, int(data_countent.strip('\n')[61:80][-2:])))
  59. k = k + 4
  60. if len(Ndataitem) > 4:
  61. Ndata.append(Ndataitem)
  62. return Ndata
  63. def head_num(lines_n):
  64. for i in range(len(lines_n)):
  65. if lines_n[i].find('END OF HEADER') != -1:
  66. data_num = i + 1
  67. return data_num

2.卫星位置以及迭代计算

  1. import math
  2. import numpy
  3. from numpy import *
  4. def nfilecompute(Ndata):
  5. #计算xyz的三维坐标
  6. xyzs = []
  7. A1=[]
  8. L1=[]
  9. #初值测站坐标-2424425.1013 5377188.1768 2418617.7454
  10. #初值化
  11. X0=mat([[0],[0],[0],[0]])
  12. sum=1
  13. #导入C1码数据即伪距观测值
  14. C1=[21937747.840,24275893.980,21322965.800,22097191.620,24075984.740, 21068789.740,20803383.780 ]
  15. C2 = [float(1/21937747.84), float(1/24275893.98), float(1/21322965.8), float(1/24606230.92), float(1/22097191.62),float( 1/24075984.74), float(1/21068789.74)]
  16. while True:
  17. for ii in range(len(Ndata)):
  18. xyz = []
  19. #系数矩阵
  20. A=[]
  21. c = 299792458 # 光速常数
  22. u = 3.986004418e14#地球引力常数
  23. a = numpy.power(float(Ndata[ii]['sqrt_A']) ,2)#卫星轨道长半径a
  24. n0 = numpy.sqrt(u/numpy.power(a , 3))#参考时刻TOE平均角速度n0
  25. n = n0 + float(Ndata[ii]['Delta_n'])#时刻未定的平均角速度n
  26. e = float(Ndata[ii]['e'])#椭圆轨道偏心率
  27. we = 7.2921151467e-5
  28. cal=[]
  29. cal.append(int(Ndata[ii]['历元'][:4])) #年
  30. cal.append(int(Ndata[ii]['历元'][5:7]))#月
  31. cal.append(int(Ndata[ii]['历元'][9:10]))#日
  32. cal.append(int(Ndata[ii]['历元'][12:13]))#时
  33. cal.append(int(Ndata[ii]['历元'][14:16]))#分
  34. cal.append(int(Ndata[ii]['历元'][17:19]))#秒
  35. #计算参考时刻的时间
  36. t_oc = cal2gps(cal)#将UTC转换为GPS周内秒
  37. #计算观测时间(历元时刻)
  38. t=cal2gps([2022,3,9,0,0])
  39. #卫星钟差改正
  40. a_0=float(Ndata[ii]['卫星钟差参数s'])
  41. a_1=float(Ndata[ii]['卫星钟漂参数s/s'])
  42. a_2=float(Ndata[ii]['卫星钟漂速度参数s/s/s'])
  43. #观测时刻2022,3,9,0,0,计算卫星钟差δt
  44. δt = a_0 + a_1*(t[1] - t_oc[1]) + a_2*((t[1]-t_oc[1])^2)
  45. # dtr = C1[ii] / c #dtr
  46. #接收机钟差
  47. dtr = float(X0[3][0])/c
  48. # print(dtr)
  49. dtsi = δt # 卫星钟差
  50. #while True:
  51. # 选择数据中的一颗卫星的观测值设伪距为C1[ii](需要迭代)
  52. # 计算卫星Sii的信号发射的概略时刻,Tsii
  53. # (a)计算卫星Sii的信号传播时间dtsii
  54. dtsii = C1[ii] / c - dtr + dtsi
  55. Tr = t[1] # Tr历元时刻
  56. # (b)计算卫星Sii的信号发射时刻Tsii
  57. Tsii = Tr - dtsii
  58. t2 = Tsii - δt
  59. #计算dtr
  60. while True:
  61. tk = t2 - float(Ndata[ii]['TEO']) # 规划时间
  62. M = float(Ndata[ii]['M0']) + n*tk#观测卫星瞬间平近点角M TOE参考时刻 t接收机接收卫星信号时刻(变量)
  63. E = computeE(M,e)#利用迭代方式解算偏近点角E
  64. f = 2 * math.atan(numpy.sqrt((1+e)/(1-e))*math.tan(E/2))
  65. _theta = f + float(Ndata[ii]['omega'])
  66. g_theta , g_r , g_i = sdgz(float(Ndata[ii]['Cuc']) , float(Ndata[ii]['Cus']) , float(Ndata[ii]['Crc']) , float(Ndata[ii]['Crs']) , float(Ndata[ii]['Cic']) , float(Ndata[ii]['Cis']) , _theta)
  67. theta = _theta + g_theta
  68. r = a * (1 - e * math.cos(E)) + g_r
  69. i = float(Ndata[ii]['i0']) + g_i + float(Ndata[ii]['IDOT']) * tk
  70. x = r * math.cos(theta)#卫星在轨道平面坐标系中的x
  71. y = r * math.sin(theta)#卫星在轨道平面坐标系中的y
  72. OMEGA = float(Ndata[ii]['OMEGA_A0']) + (float(Ndata[ii]['OMEGA_DOT']) - we)*t[1] - (float(Ndata[ii]['OMEGA_DOT']) * float(Ndata[ii]['TEO']))
  73. #计算地心地固坐标
  74. X1 = x * math.cos(OMEGA) - y * math.cos(i) * math.sin(OMEGA)
  75. Y1 = x * math.sin(OMEGA) + y * math.cos(i) * math.cos(OMEGA)
  76. Z1 = y * math.sin(i)
  77. #初始化,置测站概略位置为xyz_0,接受机钟差初值为dtr
  78. #xyz_0_coord = [0,0,0]
  79. x_0 = float(X0[0][0])
  80. y_0 = float(X0[1][0])
  81. z_0 = float(X0[2][0])
  82. # (c)计算卫星sii在Tsi的位置
  83. #计算发射时刻的卫星坐标(近似坐标),并且对卫星坐标进行地球自传改正
  84. tch=C1[ii]/c
  85. X=X1*cos(we*tch)+Y1*sin(we*tch)
  86. Y=-sin(we*tch)*X1+Y1*cos(we*tch)
  87. Z=Z1
  88. #计算近似卫星在接受时刻的坐标
  89. #计算卫星和测站的近似几何距离
  90. disct0 = numpy.sqrt(numpy.power((X - x_0), 2) + numpy.power((Y - y_0), 2) + numpy.power((Z- z_0), 2))
  91. #几何距离 求信号传播时间
  92. dts1ii=disct0/c
  93. g=dts1ii-dtsii
  94. if(abs(dts1ii-dtsii)<10.0e-7):
  95. break
  96. else:
  97. dtsii=dts1ii
  98. sum=sum+1
  99. #rs
  100. b0=-(X-x_0)/disct0
  101. b1=-(Y-y_0)/disct0
  102. b2=-(Z-z_0)/disct0
  103. b3=1
  104. #获取系数矩阵A
  105. A.append(b0)
  106. A.append(b1)
  107. A.append(b2)
  108. A.append(b3)
  109. #计算lso和L矩阵
  110. L=[]
  111. rs=disct0#卫星si到测站的几何距离
  112. psi=C1[ii]#卫星si的伪距观测值
  113. cdtsit#以米表示的卫星si的钟差
  114. dtrop=0#对流层延迟改正量,单位米,用简化的 模型计算对流层延迟改正量,单位米,用简化的模型计算
  115. diono=0#电离层延迟改正量,单位为米,采用无电离层组合观测值时,此处为0
  116. Drtcm=0#对伪距的差分改正值,此处为0
  117. lso=psi-rs+cdtsi*c-dtrop-diono+Drtcm
  118. #将计算后lso添加进L
  119. L.append(lso)
  120. xyz.append(X)
  121. xyz.append(Y)
  122. xyz.append(Z)
  123. xyzs.append(xyz)
  124. A1.append(A)
  125. L1.append(L)
  126. #将数组转为矩阵
  127. A2=mat(A1)
  128. L2=mat(L1)
  129. #计算权阵
  130. mat_P = mat(diag(C2))
  131. #加入权阵后
  132. mat_mid = A2.T * mat_P *A2
  133. ary_mid_tr = around(mat_mid.astype(float), decimals=20)
  134. mat_mid_tr = mat(ary_mid_tr)
  135. x2 = mat_mid_tr.I * A2.T * mat_P * L2
  136. Xi=X0+x2
  137. if abs(float(x2[0][0]))>0.001 and abs(float(x2[1][0]))>0.001 and abs(float(x2[2][0]))>0.001 :#or abs(float(x2[3][0]))<0.001:
  138. X0=Xi
  139. A=[]
  140. A1=[]
  141. xyzs=[]
  142. xyz=[]
  143. L=[]
  144. L1=[]
  145. else:
  146. X0=Xi
  147. print("最终的接收机坐标结果为:\n",X0)
  148. resultx=(abs(-2424425.1013-X0[0,0])/abs(-2424425.1013))*100
  149. resulty=(abs(5377188.1768-X0[1,0]) /abs(5377188.1768))*100
  150. resultz=(abs(2418617.7454-X0[2,0])/abs(2418617.7454))*100
  151. print("误差分析:\n")
  152. print("X坐标误差为百分之:{}".format(resultx))
  153. print("Y坐标误差为百分之:{}".format(resulty))
  154. print("Z坐标误差为百分之:{}".format(resultz))
  155. break
  156. return [xyzs,A1,L1,Xi]
  157. def computeE(M,e):
  158. E = 0.0
  159. while True:
  160. E0 = E
  161. E = M + e*math.sin(E0)
  162. if abs(E - E0) <0.001:
  163. break
  164. return E
  165. def sdgz(Cuc , Cus , Crc , Crs , Cic , Cis , theta):
  166. g_theta = Cuc * math.cos(2*theta) + Cus * math.sin(2 * theta)
  167. g_r = Crc * math.cos(2*theta) + Crs * math.sin(2 * theta)
  168. g_i = Cic * math.cos(2*theta) + Cis * math.sin(2 * theta)
  169. return g_theta , g_r , g_i
  170. def cal2gps(cal):
  171. # cal2gps 将公历GPS时间转换到GPS周和周内的秒
  172. # 返回列表,周和周内秒
  173. mjd=cal2mjd(cal)
  174. #GPS从MJD44244开始
  175. e=mjd-44244
  176. week=math.floor(e/7)
  177. e=e-week*7
  178. return [week,round(e*86400)]
  179. def cal2mjd(cal):
  180. # cal2jd 将公历年月日时分秒转换到简化儒略日。
  181. # 输入公历时间列表,返回儒略日
  182. if (len(cal) < 6):
  183. for i in range(len(cal), 6):
  184. cal.append(0)
  185. year = cal[0]
  186. month = cal[1]
  187. day = cal[2] + (cal[3] * 3600 + cal[4] * 60 + cal[5]) / 86400;
  188. y = year + 4800
  189. m = month
  190. if (year < 0):
  191. print('Year is wrong')
  192. return False
  193. if (m <= 2):
  194. # 1,2月视为前一年13,14月
  195. m = m + 12
  196. y = y - 1
  197. e = math.floor(30.6 * (m + 1))
  198. a = math.floor(y / 100)
  199. # 教皇格雷戈里十三世于1582年2月24日以教皇训令颁布,将1582年10月5日至14抹掉。1582年10月4日过完后第二天是10月15日
  200. if (year < 1582) or (year == 1582 and month < 10) or (year == 1582 and month == 10 and day < 15):
  201. b = -38
  202. else:
  203. b = math.floor((a / 4) - a)
  204. c = math.floor(365.25 * y)
  205. jd = b + c + e + day - 32167.5
  206. mjd = jd - 2400000.5
  207. return mjd

3.主函数编写

  1. from data import donfile
  2. from 卫星位置 import nfilecompute
  3. filename="C:\\Users\\Administrator\\Desktop\\GPS!.txt"
  4. nfilecompute(donfile(filename))

三、总结

在程序编写中,没有进行电离层改正等误差改正,没有完善模型,计算误差在米级,误差较小,可以使用,供交流学习。

标签: 算法 人工智能

本文转载自: https://blog.csdn.net/m0_49684834/article/details/128708895
版权归原作者 学测绘的小杨 所有, 如有侵权,请联系我们删除。

“【Python】伪距单点定位”的评论:

还没有评论