819 lines
34 KiB
Python
819 lines
34 KiB
Python
|
import copy
|
|||
|
import json
|
|||
|
import math
|
|||
|
import datetime
|
|||
|
from xml.etree.ElementTree import ElementTree
|
|||
|
from collections import namedtuple
|
|||
|
import numpy as np
|
|||
|
import numbers
|
|||
|
|
|||
|
# cosine in degress (math could be <a href="http://numpy.scipy.org/">numpy</a>
|
|||
|
import xmltodict
|
|||
|
|
|||
|
cosd = lambda x: np.cos(np.radians(x))
|
|||
|
# sine in degrees
|
|||
|
sind = lambda x: np.sin(np.radians(x))
|
|||
|
# tangent, in degrees
|
|||
|
tand = lambda x: np.tan(np.radians(x))
|
|||
|
# arc tan in degrees (2 arg)
|
|||
|
arctand2 = lambda y, x: np.degrees(np.arctan2(y, x))
|
|||
|
# arc tan in degrees (1 arg)
|
|||
|
arctand = lambda x: np.degrees(np.arctan(x))
|
|||
|
|
|||
|
reference_ellipsoid_params = {
|
|||
|
'a': 6378137, # 椭球长半轴 (m)
|
|||
|
'b': 6356752, # 椭球短半轴 (m)
|
|||
|
# 其他椭球参数...
|
|||
|
}
|
|||
|
LIGHTSPEED = 299792458
|
|||
|
# 第一偏心率的平方
|
|||
|
e2 = (reference_ellipsoid_params['a']**2 - reference_ellipsoid_params['b']**2) / reference_ellipsoid_params['a']**2
|
|||
|
|
|||
|
class SatelliteOrbit(object):
|
|||
|
def __init__(self) -> None:
|
|||
|
super().__init__()
|
|||
|
self.starttime = 1262275200.0
|
|||
|
self.modelName=""
|
|||
|
|
|||
|
def get_starttime(self):
|
|||
|
'''
|
|||
|
返回卫星轨道时间起算点
|
|||
|
'''
|
|||
|
return self.starttime
|
|||
|
|
|||
|
def ReconstructionSatelliteOrbit(self, GPSPoints_list):
|
|||
|
'''
|
|||
|
重建卫星轨道,使用多项式拟合法
|
|||
|
args:
|
|||
|
GPSPoints_list:GPS 卫星轨道点
|
|||
|
return:
|
|||
|
SatelliteOrbitModel 卫星轨道模型
|
|||
|
'''
|
|||
|
self.SatelliteOrbitModel = None
|
|||
|
|
|||
|
def SatelliteSpaceState(self, time_float):
|
|||
|
'''
|
|||
|
根据时间戳,返回对应时间的卫星的轨迹状态
|
|||
|
args:
|
|||
|
time_float:时间戳
|
|||
|
return:
|
|||
|
State_list:[time,Xp,Yp,Zp,Vx,Vy,Vz]
|
|||
|
'''
|
|||
|
return None
|
|||
|
|
|||
|
class SatelliteOrbitFitPoly(SatelliteOrbit):
|
|||
|
'''
|
|||
|
继承于SatelliteOribit类,为拟合多项式实现方法
|
|||
|
'''
|
|||
|
|
|||
|
def __init__(self) -> None:
|
|||
|
super().__init__()
|
|||
|
self.modelName = "多项式"
|
|||
|
self.polynum = 4
|
|||
|
|
|||
|
def ReconstructionSatelliteOrbit(self, GPSPoints_list, starttime):
|
|||
|
if len(GPSPoints_list) == 2:
|
|||
|
self.polynum = 1
|
|||
|
self.starttime = starttime
|
|||
|
|
|||
|
record_count = len(GPSPoints_list)
|
|||
|
time_arr = np.zeros((record_count, 1), dtype=np.float64) # 使用np.float64只是为了精度高些;如果32位也能满足需求,请用32位
|
|||
|
state_arr = np.zeros((record_count, 6), dtype=np.float64)
|
|||
|
A_arr = np.zeros((self.polynum + 1, 6), dtype=np.float64) # 四次项
|
|||
|
X = np.ones((record_count, self.polynum + 1), dtype=np.float64) # 记录时间坐标
|
|||
|
# 将点记录转换为自变量矩阵、因变量矩阵
|
|||
|
|
|||
|
for i in range(record_count):
|
|||
|
GPSPoint = GPSPoints_list[i]
|
|||
|
time_ = GPSPoint[0] - self.starttime # 为了保证精度,对时间进行缩放
|
|||
|
X[i, :] = np.array([1, time_])
|
|||
|
state_arr[i, :] = np.array(GPSPoint[1:], dtype=np.float64).reshape(1, 6) # 空间坐标
|
|||
|
self.model_f = []
|
|||
|
for i in range(6):
|
|||
|
Y = state_arr[:, i].reshape(-1, 1)
|
|||
|
A_arr[:, i] = np.matmul(np.matmul(np.linalg.inv(np.matmul(X.T, X)), X.T), Y)[:, 0]
|
|||
|
|
|||
|
self.A_arr = copy.deepcopy(A_arr.copy())
|
|||
|
return self.A_arr
|
|||
|
elif len(GPSPoints_list) > 6:
|
|||
|
self.polynum = 4
|
|||
|
# 多项式的节点数,理论上是超过5个可以起算,这里为了精度选择10个点起算。
|
|||
|
# 多项式 XA=Y ==> A=(X'X)^X'Y,其中 A 为待求系数,X为变量,Y为因变量
|
|||
|
# 这里使用三次项多项式,共有6组参数。
|
|||
|
# 声明自变量,因变量,系数矩阵
|
|||
|
self.starttime = starttime
|
|||
|
|
|||
|
record_count = len(GPSPoints_list)
|
|||
|
time_arr = np.zeros((record_count, 1), dtype=np.float64) # 使用np.float64只是为了精度高些;如果32位也能满足需求,请用32位
|
|||
|
state_arr = np.zeros((record_count, 6), dtype=np.float64)
|
|||
|
A_arr = np.zeros((self.polynum + 1, 6), dtype=np.float64) # 四次项
|
|||
|
X = np.ones((record_count, self.polynum + 1), dtype=np.float64) # 记录时间坐标
|
|||
|
# 将点记录转换为自变量矩阵、因变量矩阵
|
|||
|
|
|||
|
for i in range(record_count):
|
|||
|
GPSPoint = GPSPoints_list[i]
|
|||
|
time_ = GPSPoint[0] - self.starttime # 为了保证精度,对时间进行缩放
|
|||
|
X[i, :] = np.array([1, time_, time_ ** 2, time_ ** 3, time_ ** 4])
|
|||
|
state_arr[i, :] = np.array(GPSPoint[1:], dtype=np.float64).reshape(1, 6) # 空间坐标
|
|||
|
self.model_f = []
|
|||
|
for i in range(6):
|
|||
|
Y = state_arr[:, i].reshape(-1, 1)
|
|||
|
A_arr[:, i] = np.matmul(np.matmul(np.linalg.inv(np.matmul(X.T, X)), X.T), Y)[:, 0]
|
|||
|
|
|||
|
self.A_arr = copy.deepcopy(A_arr.copy())
|
|||
|
''' 测试误差
|
|||
|
from matplotlib import pyplot
|
|||
|
label_list=['x','y','z','vx','vy','vz']
|
|||
|
color_list=['r','g','b','gold','gray','pink']
|
|||
|
pyplot.figure()
|
|||
|
for i in range(6):
|
|||
|
Y = state_arr[:, i]
|
|||
|
Y_predict=self.model_f[i](X)
|
|||
|
pyplot.subplot(int("23{}".format(i+1)))
|
|||
|
d=Y-Y_predict
|
|||
|
pyplot.plot(X,d,label=label_list[i],color=color_list[i])
|
|||
|
pyplot.title("max:{}".format(np.max(d)))
|
|||
|
#self.model_f.append(interpolate.interp1d(X,Y,kind='cubic',fill_value='extrapolate'))
|
|||
|
pyplot.legend()
|
|||
|
pyplot.show()
|
|||
|
'''
|
|||
|
return self.A_arr
|
|||
|
else:
|
|||
|
self.A_arr = None
|
|||
|
return None
|
|||
|
|
|||
|
def SatelliteSpaceState(self, time_float):
|
|||
|
'''
|
|||
|
逐像素求解
|
|||
|
根据时间戳,返回对应时间的卫星的轨迹状态,会自动计算与起算时间之差
|
|||
|
args:
|
|||
|
time_float:时间戳
|
|||
|
return:
|
|||
|
State_list:[time,Xp,Yp,Zp,Vx,Vy,Vz]
|
|||
|
'''
|
|||
|
if self.model_f is None:
|
|||
|
return None
|
|||
|
|
|||
|
result_arr = np.zeros((1, 7))
|
|||
|
|
|||
|
time_float = time_float - self.starttime
|
|||
|
result_arr[0, 0] = time_float
|
|||
|
# time_arr[0, 4] = time_arr[0, 3] * time_float ** 4
|
|||
|
time_float = np.array([1, time_float, time_float ** 2, time_float ** 3, time_float ** 4]).reshape(1, 5)
|
|||
|
result_arr = np.matmul(time_float, self.A_arr)
|
|||
|
return [time_float, result_arr]
|
|||
|
|
|||
|
def getSatelliteSpaceState(self, time):
|
|||
|
'''
|
|||
|
矩阵求解
|
|||
|
根据时间戳矩阵,返回对应时刻的卫星空间状态(位置,速度),且会自动计算与起算时间之差
|
|||
|
args:
|
|||
|
time_array:nparray nx1 时间戳
|
|||
|
return:
|
|||
|
SatellitSpaceStateArray:nparray nx6 状态信息
|
|||
|
'''
|
|||
|
time_float = time.timestamp()
|
|||
|
time_float = time_float - self.starttime
|
|||
|
#
|
|||
|
px = 0
|
|||
|
py = 0
|
|||
|
pz = 0
|
|||
|
vx = 0
|
|||
|
vy = 0
|
|||
|
vz = 0
|
|||
|
for ii in range(self.polynum):
|
|||
|
px += self.A_arr[ii][0] * time_float ** ii
|
|||
|
py += self.A_arr[ii][1] * time_float ** ii
|
|||
|
pz += self.A_arr[ii][2] * time_float ** ii
|
|||
|
vx += self.A_arr[ii][3] * time_float ** ii
|
|||
|
vy += self.A_arr[ii][4] * time_float ** ii
|
|||
|
vz += self.A_arr[ii][5] * time_float ** ii
|
|||
|
sv = [px, py, pz, vx, vy, vz]
|
|||
|
return sv
|
|||
|
# if self.model_f is None:
|
|||
|
# return None # 返回None,表示没有结果
|
|||
|
# if self.polynum == 4:
|
|||
|
# n = time_array.shape[0]
|
|||
|
# result_arr_ = np.zeros((n, 6), dtype=np.float64)
|
|||
|
# time_float = time_array - self.starttime
|
|||
|
# time_float = time_float.reshape(-1) # nx1
|
|||
|
# time_arr = np.ones((time_float.shape[0], 5)) # nx5
|
|||
|
# time_arr[:, 1] = time_float
|
|||
|
# time_arr[:, 2] = time_float ** 2
|
|||
|
# time_arr[:, 3] = time_float ** 3
|
|||
|
# time_arr[:, 4] = time_float ** 4
|
|||
|
# result_arr_ = np.matmul(time_arr, self.A_arr) # nx5 5x6
|
|||
|
# # time_arr[0, 4] = time_arr[0, 3] * time_float ** 4
|
|||
|
# # result_arr=result_arr_
|
|||
|
# return result_arr_ # 位置矩阵
|
|||
|
# else:
|
|||
|
# n = time_array.shape[0]
|
|||
|
# result_arr_ = np.zeros((n, 6), dtype=np.float64)
|
|||
|
# time_float = time_array - self.starttime
|
|||
|
# time_float = time_float.reshape(-1) # nx1
|
|||
|
# time_arr = np.ones((time_float.shape[0], self.polynum + 1)) # nx5
|
|||
|
# time_arr[:, 1] = time_float
|
|||
|
# result_arr_ = np.matmul(time_arr, self.A_arr) # nx5 5x6
|
|||
|
# # time_arr[0, 4] = time_arr[0, 3] * time_float ** 4
|
|||
|
# # result_arr=result_arr_
|
|||
|
# return result_arr_ # 位置矩阵
|
|||
|
|
|||
|
class SARgps:
|
|||
|
|
|||
|
@staticmethod
|
|||
|
def xyz_to_llh(xyz):
|
|||
|
"""xyz_to_llh(xyz): returns llh=(lat (deg), lon (deg), h (meters)) for the instance ellipsoid \n
|
|||
|
given the coordinates of a point at xyz=(z,y,z) (meters). \n
|
|||
|
Based on closed form solution of H. Vermeille, Journal of Geodesy (2002) 76:451-454. \n
|
|||
|
Handles simple list or tuples (xyz represents a single point) or a list of lists or tuples (xyz represents several points)"""
|
|||
|
|
|||
|
a2 = reference_ellipsoid_params['a'] ** 2
|
|||
|
e4 = e2 ** 2
|
|||
|
# just to cast back to single list once done
|
|||
|
onePosition = False
|
|||
|
if isinstance(xyz[0], numbers.Real):
|
|||
|
xyz = [xyz]
|
|||
|
onePosition = True
|
|||
|
|
|||
|
r_llh = [0] * 3
|
|||
|
d_llh = [[0] * 3 for i in range(len(xyz))]
|
|||
|
for i in range(len(xyz)):
|
|||
|
xy2 = xyz[i][0] ** 2 + xyz[i][1] ** 2
|
|||
|
p = (xy2) / a2
|
|||
|
q = (1. - e2) * xyz[i][2] ** 2 / a2
|
|||
|
r = (p + q - e4) / 6.
|
|||
|
s = e4 * p * q / (4. * r ** 3)
|
|||
|
t = (1. + s + math.sqrt(s * (2. + s))) ** (1. / 3.)
|
|||
|
u = r * (1. + t + 1. / t)
|
|||
|
v = math.sqrt(u ** 2 + e4 * q)
|
|||
|
w = e2 * (u + v - q) / (2. * v)
|
|||
|
k = math.sqrt(u + v + w ** 2) - w
|
|||
|
D = k * math.sqrt(xy2) / (k + e2)
|
|||
|
|
|||
|
r_llh[0] = math.atan2(xyz[i][2], D)
|
|||
|
r_llh[1] = math.atan2(xyz[i][1], xyz[i][0])
|
|||
|
r_llh[2] = (k + e2 - 1.) * math.sqrt(D ** 2 + xyz[i][2] ** 2) / k
|
|||
|
|
|||
|
d_llh[i][0] = math.degrees(r_llh[0])
|
|||
|
d_llh[i][1] = math.degrees(r_llh[1])
|
|||
|
d_llh[i][2] = r_llh[2]
|
|||
|
if onePosition:
|
|||
|
return d_llh[0]
|
|||
|
else:
|
|||
|
return d_llh
|
|||
|
|
|||
|
@staticmethod
|
|||
|
def llh_to_xyz(llh):
|
|||
|
|
|||
|
"""llh_to_xyz(llh): returns (z,y,z) (meters) coordinates of a point given the point at \nllh=(lat (deg), lon (deg), h (meters)) for the instance ellipsoid\n
|
|||
|
Handles simple list or tuples (xyz represents a single point) or a list of lists or tuples (xyz represents several points)
|
|||
|
"""
|
|||
|
|
|||
|
# just to cast back to single list once done
|
|||
|
onePosition = False
|
|||
|
if isinstance(llh[0], numbers.Real):
|
|||
|
llh = [llh]
|
|||
|
onePosition = True
|
|||
|
|
|||
|
r_v = [[0] * 3 for i in range(len(llh))]
|
|||
|
|
|||
|
for i in range(len(llh)):
|
|||
|
r_lat = math.radians(llh[i][0])
|
|||
|
r_lon = math.radians(llh[i][1])
|
|||
|
hgt = llh[i][2]
|
|||
|
|
|||
|
r_re = reference_ellipsoid_params['a'] / math.sqrt(1.0 - e2 * math.sin(r_lat) ** 2)
|
|||
|
|
|||
|
r_v[i][0] = (r_re + hgt) * math.cos(r_lat) * math.cos(r_lon)
|
|||
|
r_v[i][1] = (r_re + hgt) * math.cos(r_lat) * math.sin(r_lon)
|
|||
|
r_v[i][2] = (r_re * (1.0 - e2) + hgt) * math.sin(r_lat)
|
|||
|
if onePosition:
|
|||
|
return r_v[0]
|
|||
|
else:
|
|||
|
return r_v
|
|||
|
|
|||
|
def convertToDateTime(self, string):
|
|||
|
dt = datetime.datetime.strptime(string, "%Y-%m-%dT%H:%M:%S.%f")
|
|||
|
return dt
|
|||
|
|
|||
|
def normal_radius_of_curvature(self, lat):
|
|||
|
"""East Radius (eastRad): Normal radius of curvature (N), meters for
|
|||
|
latitude in degrees """
|
|||
|
return (
|
|||
|
reference_ellipsoid_params['a'] ** 2 /
|
|||
|
((reference_ellipsoid_params['a'] * cosd(lat)) ** 2 + (reference_ellipsoid_params['b'] * sind(lat)) ** 2) ** 0.5
|
|||
|
)
|
|||
|
|
|||
|
|
|||
|
def LatLonHgt2XYZ(self, lat, lon, h):
|
|||
|
"""LatLonHgt2XYZ(lat, lon, h) --> (x, y, z)
|
|||
|
|
|||
|
lat is the latitude (deg)
|
|||
|
lon is the longitude (deg)
|
|||
|
h is the heigh (m)
|
|||
|
|
|||
|
(x, y, z) is a tuple of ECEF coordinates (m)
|
|||
|
"""
|
|||
|
N = self.normal_radius_of_curvature(lat)
|
|||
|
cos_lat = cosd(lat)
|
|||
|
X = cos_lat * cosd(lon) * (N + h)
|
|||
|
Y = cos_lat * sind(lon) * (N + h)
|
|||
|
Z = sind(lat) * ((1 - e2) * N + h)
|
|||
|
return (X, Y, Z)
|
|||
|
|
|||
|
def FindInfomationFromJson(self, HeaderFile_dom_json, node_path_list):
|
|||
|
"""
|
|||
|
在Json文件中,按照指定路径解析出制定节点
|
|||
|
"""
|
|||
|
result_node = HeaderFile_dom_json
|
|||
|
for nodename in node_path_list:
|
|||
|
result_node = result_node[nodename]
|
|||
|
return result_node
|
|||
|
|
|||
|
def ReconstructionSatelliteOrbit(self, GPSPoints_list, starttime):
|
|||
|
if len(GPSPoints_list) == 2:
|
|||
|
self.polynum = 1
|
|||
|
self.starttime = starttime
|
|||
|
|
|||
|
record_count = len(GPSPoints_list)
|
|||
|
time_arr = np.zeros((record_count, 1), dtype=np.float64) # 使用np.float64只是为了精度高些;如果32位也能满足需求,请用32位
|
|||
|
state_arr = np.zeros((record_count, 6), dtype=np.float64)
|
|||
|
A_arr = np.zeros((self.polynum + 1, 6), dtype=np.float64) # 四次项
|
|||
|
X = np.ones((record_count, self.polynum + 1), dtype=np.float64) # 记录时间坐标
|
|||
|
# 将点记录转换为自变量矩阵、因变量矩阵
|
|||
|
|
|||
|
for i in range(record_count):
|
|||
|
GPSPoint = GPSPoints_list[i]
|
|||
|
time_ = GPSPoint[0] - self.starttime # 为了保证精度,对时间进行缩放
|
|||
|
X[i, :] = np.array([1, time_])
|
|||
|
state_arr[i, :] = np.array(GPSPoint[1:], dtype=np.float64).reshape(1, 6) # 空间坐标
|
|||
|
self.model_f = []
|
|||
|
for i in range(6):
|
|||
|
Y = state_arr[:, i].reshape(-1, 1)
|
|||
|
A_arr[:, i] = np.matmul(np.matmul(np.linalg.inv(np.matmul(X.T, X)), X.T), Y)[:, 0]
|
|||
|
|
|||
|
self.A_arr = copy.deepcopy(A_arr.copy())
|
|||
|
return self.A_arr
|
|||
|
elif len(GPSPoints_list) > 6:
|
|||
|
# 多项式的节点数,理论上是超过5个可以起算,这里为了精度选择10个点起算。
|
|||
|
# 多项式 XA=Y ==> A=(X'X)^X'Y,其中 A 为待求系数,X为变量,Y为因变量
|
|||
|
# 这里使用三次项多项式,共有6组参数。
|
|||
|
# 声明自变量,因变量,系数矩阵
|
|||
|
self.starttime = starttime
|
|||
|
|
|||
|
record_count = len(GPSPoints_list)
|
|||
|
time_arr = np.zeros((record_count, 1), dtype=np.float64) # 使用np.float64只是为了精度高些;如果32位也能满足需求,请用32位
|
|||
|
state_arr = np.zeros((record_count, 6), dtype=np.float64)
|
|||
|
A_arr = np.zeros((self.polynum, 6), dtype=np.float64) # 四次项
|
|||
|
X = np.ones((record_count, self.polynum), dtype=np.float64) # 记录时间坐标
|
|||
|
# 将点记录转换为自变量矩阵、因变量矩阵
|
|||
|
|
|||
|
for i in range(record_count):
|
|||
|
GPSPoint = GPSPoints_list[i]
|
|||
|
time_ = GPSPoint[0] - self.starttime # 为了保证精度,对时间进行缩放
|
|||
|
X[i, :] = np.array(list(map(lambda ii: time_ ** ii, range(self.polynum))))
|
|||
|
state_arr[i, :] = np.array(GPSPoint[1:], dtype=np.float64).reshape(1, 6) # 空间坐标
|
|||
|
self.model_f = []
|
|||
|
for i in range(6):
|
|||
|
Y = state_arr[:, i].reshape(-1, 1)
|
|||
|
A_arr[:, i] = np.matmul(np.matmul(np.linalg.inv(np.matmul(X.T, X)), X.T), Y)[:, 0]
|
|||
|
|
|||
|
self.A_arr = A_arr.copy()
|
|||
|
return self.A_arr
|
|||
|
else:
|
|||
|
self.A_arr = None
|
|||
|
return None
|
|||
|
|
|||
|
def getGPSModel(self, xml_path):
|
|||
|
GPSLists = []
|
|||
|
root = ElementTree(file=xml_path).getroot()
|
|||
|
with open(xml_path, 'r', encoding='utf-8') as fp:
|
|||
|
HeaderFile_dom_str = fp.read()
|
|||
|
HeaderFile_dom = xmltodict.parse(HeaderFile_dom_str) # 将XML转成json文本
|
|||
|
HeaderFile_dom_json = json.loads(json.dumps(HeaderFile_dom)) # 将json字符串,转成json对象(对应于python中的dict)
|
|||
|
GPSNode = ['level1Product','platform','orbit', 'stateVec']
|
|||
|
GPSNodeNames = ['timeUTC', 'posX', 'posY', 'posZ', 'velX', 'velY', 'velZ']
|
|||
|
GPSTime = "%Y-%m-%dT%H:%M:%S.%f"
|
|||
|
GPSPoints = self.FindInfomationFromJson(HeaderFile_dom_json, GPSNode)
|
|||
|
dataStartTime = self.convertToDateTime(
|
|||
|
root.find("productInfo").find("sceneInfo").find("start").find("timeUTC").text).timestamp()
|
|||
|
dataStopTime = self.convertToDateTime(
|
|||
|
root.find("productInfo").find("sceneInfo").find("stop").find("timeUTC").text).timestamp()
|
|||
|
centerTime = (dataStopTime - dataStartTime) / 2 + dataStartTime
|
|||
|
|
|||
|
for GPSPoint in GPSPoints:
|
|||
|
GPSPoint = [
|
|||
|
datetime.datetime.strptime(GPSPoint[GPSNodeNames[0]], GPSTime).timestamp(), # TimeStamp
|
|||
|
float(GPSPoint[GPSNodeNames[1]]), # Xp
|
|||
|
float(GPSPoint[GPSNodeNames[2]]), # Yp
|
|||
|
float(GPSPoint[GPSNodeNames[3]]), # Zp
|
|||
|
float(GPSPoint[GPSNodeNames[4]]), # Vx
|
|||
|
float(GPSPoint[GPSNodeNames[5]]), # Vy
|
|||
|
float(GPSPoint[GPSNodeNames[6]])] # VZ
|
|||
|
GPSLists.append(GPSPoint)
|
|||
|
SatelliteOrbitModel = SatelliteOrbitFitPoly()
|
|||
|
if SatelliteOrbitModel.ReconstructionSatelliteOrbit(GPSLists, centerTime) is None:
|
|||
|
return None
|
|||
|
return SatelliteOrbitModel
|
|||
|
|
|||
|
def calBaseline(self, slantRange_m, azimuthTime_m, azimuthTime_a, SatelliteOrbit_m, SatelliteOrbit_a, wvl, mas_xml, aux_xml):
|
|||
|
start = datetime.datetime.now()
|
|||
|
aux_referenceTime = self.getReferenceTime(aux_xml)
|
|||
|
Bpar = np.zeros((len(azimuthTime_m), len(slantRange_m)), dtype=np.float32)
|
|||
|
Bperp = np.zeros((len(azimuthTime_m), len(slantRange_m)), dtype=np.float32)
|
|||
|
for ii, taz in enumerate(azimuthTime_m):
|
|||
|
referenceSV = SatelliteOrbit_m.getSatelliteSpaceState(taz)
|
|||
|
mxyz = np.array(referenceSV[0:3])
|
|||
|
mvel = np.array(referenceSV[3:6])
|
|||
|
for jj, rng in enumerate(slantRange_m):
|
|||
|
# start = datetime.datetime.now()
|
|||
|
llh = self.rdr2geo(referenceSV, taz, rng, wvl, SatelliteOrbit_m, azimuthTime_m, slantRange_m, mas_xml)
|
|||
|
|
|||
|
tarxyz_temp = self.LatLonHgt2XYZ(llh[0], llh[1], llh[2])
|
|||
|
targxyz = np.array((tarxyz_temp[0], tarxyz_temp[1], tarxyz_temp[2]))
|
|||
|
|
|||
|
slvTime, slvrng = self.geo2rdr(llh, azimuthTime_a, SatelliteOrbit_a, wvl, aux_referenceTime)
|
|||
|
# end = datetime.datetime.now()
|
|||
|
# deffT = (end - start).total_seconds()
|
|||
|
# print('消耗时间为: ' + str(deffT))
|
|||
|
secondarySV = SatelliteOrbit_a.getSatelliteSpaceState(slvTime)
|
|||
|
sxyz = np.array(secondarySV[0:3])
|
|||
|
aa = np.linalg.norm(sxyz - mxyz)
|
|||
|
costheta = (rng * rng + aa * aa - slvrng * slvrng) / (2. * rng * aa)
|
|||
|
|
|||
|
Bpar[ii, jj] = aa * costheta
|
|||
|
|
|||
|
perp = aa * np.sqrt(1 - costheta * costheta)
|
|||
|
direction = np.sign(np.dot(np.cross(targxyz - mxyz, sxyz - mxyz), mvel))
|
|||
|
Bperp[ii, jj] = direction * perp
|
|||
|
end = datetime.datetime.now()
|
|||
|
deffT = (end - start).total_seconds()
|
|||
|
print('消耗时间为: ' + str(deffT))
|
|||
|
return Bpar, Bperp
|
|||
|
|
|||
|
def rdr2geo(self, sv, taz, rng, wvl, SatelliteOrbit_m, azimuthTime, slantRange, mas_xml, height=0., side=-1):
|
|||
|
|
|||
|
hdg = self.getENUHeading(SatelliteOrbit_m, taz)
|
|||
|
# sv = SatelliteOrbit_m.getSatelliteSpaceState(taz)
|
|||
|
pos = sv[0:3]
|
|||
|
vel = sv[3:6]
|
|||
|
# vmag = np.linalg.norm(vel)
|
|||
|
dopfact = 0.0
|
|||
|
# dopfact = self.getDoppler(taz, rng, azimuthTime, slantRange, mas_xml) * 0.5 * wvl * rng / vmag
|
|||
|
satLLH = self.xyz_to_llh(pos)
|
|||
|
self.setSCH(satLLH[0], satLLH[1], hdg)
|
|||
|
radius = self.pegRadCur
|
|||
|
|
|||
|
satVec = np.array(pos)
|
|||
|
velVec = np.array(vel)
|
|||
|
|
|||
|
###Setup TCN basis
|
|||
|
clat = np.cos(np.radians(satLLH[0]))
|
|||
|
slat = np.sin(np.radians(satLLH[0]))
|
|||
|
clon = np.cos(np.radians(satLLH[1]))
|
|||
|
slon = np.sin(np.radians(satLLH[1]))
|
|||
|
nhat = np.array([-clat * clon, -clat * slon, -slat])
|
|||
|
temp = np.cross(nhat, velVec)
|
|||
|
chat = temp / np.linalg.norm(temp)
|
|||
|
temp = np.cross(chat, nhat)
|
|||
|
that = temp / np.linalg.norm(temp)
|
|||
|
vhat = velVec / np.linalg.norm(velVec)
|
|||
|
|
|||
|
zsch = height
|
|||
|
|
|||
|
# for ii in range(10):
|
|||
|
###Near nadir tests
|
|||
|
if (satLLH[2] - zsch) >= rng:
|
|||
|
return None
|
|||
|
|
|||
|
a = (satLLH[2] + radius)
|
|||
|
b = (radius + zsch)
|
|||
|
|
|||
|
costheta = 0.5 * (a / rng + rng / a - (b / a) * (b / rng))
|
|||
|
sintheta = np.sqrt(1 - costheta * costheta)
|
|||
|
|
|||
|
gamma = rng * costheta
|
|||
|
alpha = dopfact - gamma * np.dot(nhat, vhat) / np.dot(vhat, that)
|
|||
|
beta = -side * np.sqrt(rng * rng * sintheta * sintheta - alpha * alpha)
|
|||
|
|
|||
|
delta = alpha * that + beta * chat + gamma * nhat
|
|||
|
|
|||
|
targVec = satVec + delta
|
|||
|
|
|||
|
targLLH = self.xyz_to_llh(list(targVec))
|
|||
|
# targXYZ = self.llh_to_xyz([targLLH[0], targLLH[1], height])
|
|||
|
# targSCH = self.xyz_to_sch(targXYZ)
|
|||
|
#
|
|||
|
# zsch = targSCH[2]
|
|||
|
#
|
|||
|
# rdiff = rng - np.linalg.norm(np.array(satVec) - np.array(targXYZ))
|
|||
|
|
|||
|
return targLLH
|
|||
|
|
|||
|
def geo2rdr(self, llh, azimuthTime_a, SatelliteOrbit_a, wvl, aux_referenceTime):
|
|||
|
xyz = self.llh_to_xyz(llh)
|
|||
|
tguess = azimuthTime_a[0]
|
|||
|
if wvl == 0:
|
|||
|
outOfBounds = False
|
|||
|
for ii in range(51):
|
|||
|
try:
|
|||
|
sv = SatelliteOrbit_a.getSatelliteSpaceState(tguess) # 获取卫星的 位置、速度
|
|||
|
except Exception as e:
|
|||
|
print(e)
|
|||
|
outOfBounds = True
|
|||
|
break
|
|||
|
pos = np.array(sv[0:3]) # 卫星坐标
|
|||
|
vel = np.array(sv[3:6]) # 卫星速度
|
|||
|
dr = xyz - pos
|
|||
|
rng = np.linalg.norm(dr) # 求斜距
|
|||
|
dopfact = np.dot(dr, vel) # fd 公式
|
|||
|
fdop = 0 # doppler(DTU.seconds_since_midnight(tguess), rng) * wvl * 0.5
|
|||
|
fdopder = 0 # (0.5 * wvl * doppler(DTU.seconds_since_midnight(tguess), rng + 10.0) - fdop) / 10.0
|
|||
|
fn = dopfact - fdop * rng
|
|||
|
c1 = -np.dot(vel, vel)
|
|||
|
c2 = (fdop / rng + fdopder)
|
|||
|
fnprime = c1 + c2 * dopfact
|
|||
|
tguess = tguess - datetime.timedelta(seconds=fn / fnprime)
|
|||
|
if outOfBounds:
|
|||
|
raise Exception('Interpolation time out of bounds')
|
|||
|
else:
|
|||
|
dt = 0.0001
|
|||
|
outOfBounds = False
|
|||
|
for ii in range(51):
|
|||
|
try:
|
|||
|
sv = SatelliteOrbit_a.getSatelliteSpaceState(tguess + datetime.timedelta(seconds=dt)) # 获取卫星的 位置、速度
|
|||
|
except Exception as e:
|
|||
|
print(e)
|
|||
|
outOfBounds = True
|
|||
|
break
|
|||
|
|
|||
|
pos1 = np.array(sv[0:3]) # 卫星坐标
|
|||
|
vel1 = np.array(sv[3:6]) # 卫星速度
|
|||
|
dr1 = pos1 - xyz
|
|||
|
rng1 = np.linalg.norm(dr1) # 斜距
|
|||
|
|
|||
|
FdTheory1 = -2 / (rng1 * wvl) * np.dot(dr1, vel1)
|
|||
|
try:
|
|||
|
sv = SatelliteOrbit_a.getSatelliteSpaceState(tguess)
|
|||
|
except Exception as e:
|
|||
|
print(e)
|
|||
|
outOfBounds = True
|
|||
|
break
|
|||
|
pos2 = np.array(sv[0:3]) # 卫星坐标
|
|||
|
vel2 = np.array(sv[3:6]) # 卫星速度
|
|||
|
dr2 = pos2 - xyz
|
|||
|
rng = np.linalg.norm(dr2) # 斜距
|
|||
|
FdTheory2 = -2 / (rng * wvl) * np.dot(dr2, vel2)
|
|||
|
TSR = rng * 2 / LIGHTSPEED - aux_referenceTime # nx1
|
|||
|
|
|||
|
FdNumerical = 0
|
|||
|
|
|||
|
fdopper_grad = (FdTheory1 - FdTheory2) / dt
|
|||
|
inc_t = (FdTheory2 - FdNumerical) / fdopper_grad
|
|||
|
tguess = tguess - datetime.timedelta(seconds=inc_t)
|
|||
|
if abs(inc_t) < 1e-6:
|
|||
|
break
|
|||
|
else:
|
|||
|
t_prev_guess = tguess
|
|||
|
if outOfBounds:
|
|||
|
raise Exception('Interpolation time out of bounds')
|
|||
|
return tguess, rng
|
|||
|
|
|||
|
def getDoppler(self, taz, rng, azimuthTime, slantRange, xml_path):
|
|||
|
with open(xml_path, 'r', encoding='utf-8') as fp:
|
|||
|
HeaderFile_dom_str = fp.read()
|
|||
|
HeaderFile_dom = xmltodict.parse(HeaderFile_dom_str) # 将XML转成json文本
|
|||
|
HeaderFile_dom_json = json.loads(json.dumps(HeaderFile_dom))
|
|||
|
DopplerRates = self.FindInfomationFromJson(HeaderFile_dom_json, ['level1Product','processing',"geometry", 'dopplerRate', 'dopplerRatePolynomial', 'coefficient'])
|
|||
|
dr = float(self.FindInfomationFromJson(HeaderFile_dom_json, ['level1Product','productInfo','imageDataInfo', 'imageRaster','columnSpacing']).get('#text'))
|
|||
|
DopplerRate = []
|
|||
|
for doppler in DopplerRates:
|
|||
|
DopplerRate.append(float(doppler.get('#text')))
|
|||
|
dcoeffs = []
|
|||
|
for ind, val in enumerate(DopplerRate):
|
|||
|
dcoeffs.append(val / (dr ** ind))
|
|||
|
coeffs = self.getCoeffs(dcoeffs)
|
|||
|
|
|||
|
dopplerFat = 0.
|
|||
|
meanAzimuth = azimuthTime[0].timestamp()
|
|||
|
normAzimuth = azimuthTime[-1].timestamp() - meanAzimuth
|
|||
|
meanRange = slantRange[0]
|
|||
|
normRange = slantRange[-1]
|
|||
|
|
|||
|
y = (taz - meanAzimuth) / normAzimuth
|
|||
|
x = (rng - meanRange) / normRange
|
|||
|
for ii, row in enumerate(coeffs):
|
|||
|
yfact = y ** ii
|
|||
|
for jj, col in enumerate(row):
|
|||
|
dopplerFat += coeffs[ii][jj] * yfact * (x**jj)
|
|||
|
return dopplerFat
|
|||
|
|
|||
|
def getCoeffs(self, dcoeffs):
|
|||
|
coeffs = [[0. for i in j] for j in dcoeffs]
|
|||
|
for ii, row in enumerate(dcoeffs):
|
|||
|
for jj, col in enumerate(row):
|
|||
|
coeffs[ii][jj] = float(col)
|
|||
|
return coeffs
|
|||
|
|
|||
|
def getReferenceTime(self, xml_path):
|
|||
|
root = ElementTree(file=xml_path).getroot()
|
|||
|
referenceTime = float(root.find("processing").find("geometry").find("dopplerRate").find("dopplerRatePolynomial").find("referencePoint").text)
|
|||
|
return referenceTime
|
|||
|
|
|||
|
def getENUHeading(self,SatelliteOrbit, time):
|
|||
|
'''
|
|||
|
Compute heading at given azimuth time using single state vector.
|
|||
|
If time is not provided, mid point of orbit is used.
|
|||
|
'''
|
|||
|
|
|||
|
vec1 = SatelliteOrbit.getSatelliteSpaceState(time)
|
|||
|
llh1 = self.xyz_to_llh(vec1[0:3])
|
|||
|
|
|||
|
enumat = self.enubasis(llh1)
|
|||
|
venu = np.dot(enumat.xyz_to_enu, vec1[3:6])
|
|||
|
hdg = np.arctan2(venu[0, 0], venu[0, 1])
|
|||
|
return np.degrees(hdg)
|
|||
|
|
|||
|
def enubasis(self, posLLH):
|
|||
|
"""
|
|||
|
xyzenuMat = elp.enubasis(posLLH)
|
|||
|
Given an instance elp of an Ellipsoid LLH position (as a list) return the
|
|||
|
transformation matrices from the XYZ frame to the ENU frame and the
|
|||
|
inverse from the ENU frame to the XYZ frame.
|
|||
|
The returned object is a namedtuple with numpy matrices in elements
|
|||
|
named 'enu_to_xyz' and 'xyz_to_enu'
|
|||
|
enu_to_xyzMat = (elp.enubasis(posLLH)).enu_to_xyz
|
|||
|
xyz_to_enuMat = (elp.enubasis(posLLH)).xyz_to_enu
|
|||
|
"""
|
|||
|
|
|||
|
import numpy
|
|||
|
r_lat = numpy.radians(posLLH[0])
|
|||
|
r_lon = numpy.radians(posLLH[1])
|
|||
|
|
|||
|
r_clt = numpy.cos(r_lat)
|
|||
|
r_slt = numpy.sin(r_lat)
|
|||
|
r_clo = numpy.cos(r_lon)
|
|||
|
r_slo = numpy.sin(r_lon)
|
|||
|
|
|||
|
r_enu_to_xyzMat = numpy.matrix([
|
|||
|
[-r_slo, -r_slt * r_clo, r_clt * r_clo],
|
|||
|
[r_clo, -r_slt * r_slo, r_clt * r_slo],
|
|||
|
[0.0, r_clt, r_slt]])
|
|||
|
|
|||
|
r_xyz_to_enuMat = r_enu_to_xyzMat.transpose()
|
|||
|
enuxyzMat = namedtuple("enuxyzMat", "enu_to_xyz xyz_to_enu")
|
|||
|
return enuxyzMat(r_enu_to_xyzMat, r_xyz_to_enuMat)
|
|||
|
|
|||
|
def setSCH(self, pegLat, pegLon, pegHdg, pegHgt=0.0):
|
|||
|
"""
|
|||
|
Set up an SCH coordinate system at the given peg point.
|
|||
|
Set a peg point on the ellipse at pegLat, pegLon, pegHdg (in degrees).
|
|||
|
Set the radius of curvature and the transformation matrix and offset
|
|||
|
vector needed to transform between (s,c,h) and ecef (x,y,z).
|
|||
|
"""
|
|||
|
self.pegLat = pegLat
|
|||
|
self.pegLon = pegLon
|
|||
|
self.pegHdg = pegHdg
|
|||
|
self.pegHgt = pegHgt
|
|||
|
self.pegLLH = [pegLat, pegLon, pegHgt]
|
|||
|
|
|||
|
# determine the radius of curvature at the peg point, i.e, the
|
|||
|
# the radius of the SCH sphere
|
|||
|
self.pegRadCur = self.radiusOfCurvature(self.pegLLH, pegHdg)
|
|||
|
|
|||
|
# # determine the rotation matrix (from radar_to_xyz.F)
|
|||
|
# r_lat = np.radians(pegLat)
|
|||
|
# r_lon = np.radians(pegLon)
|
|||
|
# r_hdg = np.radians(pegHdg)
|
|||
|
# r_clt = np.cos(r_lat)
|
|||
|
# r_slt = np.sin(r_lat)
|
|||
|
# r_clo = np.cos(r_lon)
|
|||
|
# r_slo = np.sin(r_lon)
|
|||
|
# r_chg = np.cos(r_hdg)
|
|||
|
# r_shg = np.sin(r_hdg)
|
|||
|
#
|
|||
|
# ptm11 = r_clt * r_clo
|
|||
|
# ptm12 = -r_shg * r_slo - r_slt * r_clo * r_chg
|
|||
|
# ptm13 = r_slo * r_chg - r_slt * r_clo * r_shg
|
|||
|
# ptm21 = r_clt * r_slo
|
|||
|
# ptm22 = r_clo * r_shg - r_slt * r_slo * r_chg
|
|||
|
# ptm23 = -r_clo * r_chg - r_slt * r_slo * r_shg
|
|||
|
# ptm31 = r_slt
|
|||
|
# ptm32 = r_clt * r_chg
|
|||
|
# ptm33 = r_clt * r_shg
|
|||
|
#
|
|||
|
# self.pegRotMatNP = np.matrix(
|
|||
|
# [[ptm11, ptm12, ptm13],
|
|||
|
# [ptm21, ptm22, ptm23],
|
|||
|
# [ptm31, ptm32, ptm33]]
|
|||
|
# )
|
|||
|
# self.pegRotMatInvNP = self.pegRotMatNP.transpose()
|
|||
|
#
|
|||
|
# self.pegRotMat = self.pegRotMatNP.tolist()
|
|||
|
# self.pegRotMatInv = self.pegRotMatInvNP.tolist()
|
|||
|
#
|
|||
|
# # find the translation vector as a column matrix
|
|||
|
# self.pegXYZ = self.llh_to_xyz(self.pegLLH)
|
|||
|
# self.pegXYZNP = np.matrix(self.pegXYZ).transpose()
|
|||
|
#
|
|||
|
# # Outward normal to ellispoid at the peg point
|
|||
|
# self.pegNormal = [r_clt * r_clo, r_clt * r_slo, r_slt]
|
|||
|
# self.pegNormalNP = np.matrix(self.pegNormal).transpose()
|
|||
|
#
|
|||
|
# # Offset Vector - to center of SCH sphere
|
|||
|
# self.pegOVNP = self.pegXYZNP - self.pegRadCur * self.pegNormalNP
|
|||
|
# self.pegOV = self.pegOVNP.transpose().tolist()[0]
|
|||
|
return
|
|||
|
|
|||
|
def radiusOfCurvature(self, llh, hdg=0):
|
|||
|
"""
|
|||
|
radiusOfCurvature(llh,[hdg]): returns Radius of Curvature (meters)
|
|||
|
in the direction specified by hdg for the instance ellipsoid
|
|||
|
given a position llh=(lat (deg), lon (deg), h (meters)).
|
|||
|
If no heading is given the default is 0, or North.
|
|||
|
"""
|
|||
|
|
|||
|
r_lat = math.radians(llh[0])
|
|||
|
r_hdg = math.radians(hdg)
|
|||
|
|
|||
|
reast = self.eastRadiusOfCurvature(llh)
|
|||
|
rnorth = self.northRadiusOfCurvature(llh)
|
|||
|
|
|||
|
# radius of curvature for point on ellipsoid
|
|||
|
rdir = (reast * rnorth) / (
|
|||
|
reast * math.cos(r_hdg) ** 2 + rnorth * math.sin(r_hdg) ** 2)
|
|||
|
|
|||
|
# add height of the llh point
|
|||
|
return rdir + llh[2]
|
|||
|
|
|||
|
def eastRadiusOfCurvature(self, llh):
|
|||
|
"""eastRadiusOfCurvature(llh): returns Radius of Curvature (meters) \nin the East direction for the instance
|
|||
|
ellipsoid \ngiven a position llh=(lat (deg), lon (deg), h (meters))"""
|
|||
|
|
|||
|
r_lat = math.radians(llh[0])
|
|||
|
|
|||
|
reast = reference_ellipsoid_params['a'] / math.sqrt(1.0 - e2 * math.sin(r_lat) ** 2)
|
|||
|
return reast
|
|||
|
##
|
|||
|
# Compute the radius of curvature in the north direction on an ellipsoid
|
|||
|
def northRadiusOfCurvature(self, llh):
|
|||
|
"""northRadiusOfCurvature(llh): returns Radius of Curvature (meters) \nin the North direction for the instance
|
|||
|
ellipsoid \ngiven a position llh=(lat (deg), lon (deg), h (meters))"""
|
|||
|
|
|||
|
r_lat = math.radians(llh[0])
|
|||
|
|
|||
|
rnorth = (reference_ellipsoid_params['a'] * (1.0 - e2)) / (1.0 - e2 * math.sin(r_lat) ** 2) ** (1.5)
|
|||
|
return rnorth
|
|||
|
|
|||
|
# 距离方程计算
|
|||
|
@staticmethod
|
|||
|
def compute_distance(slant_range, doppler_frequency):
|
|||
|
c = 3 * 10**8 # 光速
|
|||
|
distance = (c * doppler_frequency) / (2 * slant_range)
|
|||
|
return distance
|
|||
|
|
|||
|
|
|||
|
# 高度方程(假设直接投影到地球表面)
|
|||
|
@staticmethod
|
|||
|
def compute_height(slant_range, incident_angle, reference_ellipsoid_params):
|
|||
|
a = reference_ellipsoid_params['a']
|
|||
|
b = reference_ellipsoid_params['b']
|
|||
|
q = np.sqrt((slant_range**2))
|
|||
|
w = ((a**2) * (np.sin(incident_angle)**2))
|
|||
|
height = np.sqrt((slant_range**2) - ((a**2) * (np.sin(incident_angle)**2))) - b
|
|||
|
return height
|
|||
|
|
|||
|
|
|||
|
# 计算P点在参考椭球面上的等斜距投影点P0的坐标
|
|||
|
@staticmethod
|
|||
|
def compute_P0_coordinates(latitude_P, longitude_P, height_P0):
|
|||
|
a = reference_ellipsoid_params['a']
|
|||
|
e_squared = 1 - ((reference_ellipsoid_params['b']**2) / (reference_ellipsoid_params['a']**2))
|
|||
|
|
|||
|
N = a / math.sqrt(1 - e_squared * math.sin(math.radians(latitude_P))**2)
|
|||
|
X = (N + height_P0) * math.cos(math.radians(latitude_P)) * math.cos(math.radians(longitude_P))
|
|||
|
Y = (N + height_P0) * math.cos(math.radians(latitude_P)) * math.sin(math.radians(longitude_P))
|
|||
|
Z = (N * (1 - e_squared) + height_P0) * math.sin(math.radians(latitude_P))
|
|||
|
return X, Y, Z
|
|||
|
|
|||
|
|
|||
|
if __name__ == '__main__':
|
|||
|
sGps = SARgps()
|
|||
|
|
|||
|
# 假设P点的经纬度已知
|
|||
|
latitude_P = 40.0 # P点纬度
|
|||
|
longitude_P = -100.0 # P点经度
|
|||
|
h = 5000
|
|||
|
xyz = sGps.llh_to_xyz([latitude_P, longitude_P, h])
|
|||
|
print(xyz)
|
|||
|
llh = sGps.xyz_to_llh(xyz)
|
|||
|
print(llh)
|
|||
|
distance_P = sGps.compute_distance(slant_range, doppler_frequency)
|
|||
|
|
|||
|
# 方位方程(假设一些参数)
|
|||
|
incident_angle = 30 # 入射角
|
|||
|
azimuth = math.radians(45) # 方位角
|
|||
|
height_P0 = sGps.compute_height(slant_range, incident_angle, reference_ellipsoid_params)
|
|||
|
|
|||
|
P0_coordinates = sGps.compute_P0_coordinates(latitude_P, longitude_P, height_P0)
|
|||
|
print("P0点在参考椭球面上的等斜距投影点坐标:", P0_coordinates)
|